跳至正文
首页 » 博客 » Using VS Code and Node to Write HTML with Style (Baked-in)!

Using VS Code and Node to Write HTML with Style (Baked-in)!

导言

在本文中,我将解释如何使用Visual Studio CodeNode.js的强大功能来构建自定义编辑工具,以克服常规博客平台并编写Markdown

本文的细节是针对我们遇到的问题量身定制的,但是这里涉及的策略可以应用于大量的任务,您希望使用Markdown为遗留系统创建一些内容,或者创建其他更有趣的自定义编辑器工作流。例如,假设您想编写一些HTML以包含在电子邮件中,那么您在可以使用的标记方面受到很大限制。

的问题

Infragistics已经提供论坛和博客很长一段时间了,而且,当你需要保持一个大型的内容库可访问时,经常发生,运行一些相当旧的博客软件, 工作 ,但不一定是超级愉快工作。将内容导入系统的主要载体包括:

  • 使用一个有bug的基于web的WYSIWYG编辑器,它不支持很好地输入代码片段,并且错误地往返现有内容,如果您再次编辑它,导致内容以不可预测的方式改变。
  • 使用上述buggy基于web的WYSIWYG编辑器上的按钮注入文字HTML代码,将注入的HTML强制转换为有时有bug的表单,大概是为了防止不安全的模式,但通常会导致事情看起来不像作者的意图。
  • 工作黑暗的魔法,并在系统上与模糊的单点登录作斗争,以吸引Windows Live Writer (现在打开Live Writer) 直到web服务接口并从那里注入内容,才发现博客引擎仍然以不希望的方式破坏提交的HTML。

除了将内容实际获取到系统中的困难之外,还有一个事实是,Infragistics博客内容在代码片段的使用上很重要。这些应该,理想情况下,看起来不错,并有语法高亮。

如果你使用像Github Gist这样的代码片段存储服务,你可能会认为这部分很容易,但我们的问题是,博客软件专门抑制和删除帖子内容中的iframe元素。我相信这是一个安全的自负,因为就编辑而言,引擎没有充分准备在帖子内容和评论内容之间进行划分,并且您不希望您的评论作者注入iframe!

不幸的是,大多数体面的外部代码片段软件希望将代码片段加载到iframe中,或者需要自定义JavaScript才能运行 (就我们的博客引擎而言,这是另一个no-no)。

有一段时间,我们在网站级别运行了一些JavaScript,它会对以非常精确的方式格式化的pre标记应用一些语法突出显示,但是每当我们的网站团队对网站进行一些重大修订时,这个JavaScript就会丢失,导致所有依赖它的文章突然看起来很糟糕。当最近一次失踪时,我开始烹饪这个解决方案。

最后,在一个专有的博客门户网站中使用WYSIWYG编辑器并不能让你在内容上线之前对其进行审查和迭代。理想情况下,有人应该能够在发布之前要求同行或文案编辑对博客文章进行审查。我们对此最接近的近似是发布未列出的草稿帖子,并请求反馈。但是,没有办法对内联内容进行注释和注释,就像您可以说的那样,存储在git中的markdown文件使用拉取请求工作流所做的更改。

现在,谢天谢地,我确信我们很快就会更新我们的博客软件,更新到一个更近的引擎,所以这是我正在解决的一个短期问题 (希望),但这个短期解决方案并不难创建,更新后可能会继续相关,并提供了一个很好的策略来创建自定义编辑工作流程,以解决与我们类似的问题。由于创作和迭代内容的障碍,我们的许多工程师会减少或根本不写博客,降低这些障碍会鼓励更多的内容。

该计划

好,让我们总结一下要克服的问题:

  • 除了将文字HTML注入当前系统之外,做任何事情都是相当困难的,甚至这需要小心,因为有许多HTML模式会被系统忽略、破坏或歪曲。
  • 使用博客引擎的WYSIWYG编辑器甚至Open Live Writer是一个很大的痛苦,尤其是在使用代码片段或迭代内容时。
  • 我们需要看起来不错的代码片段,并且当一些外部javascript丢失时不会爆炸。
  • 我们需要一些方法来对内容进行审查。

这里有一个解决问题的计划:

  • VS Code是免费的,并且在编辑Markdown文件时具有出色的并排markdown预览。
  • Node.js和一饮而尽让我们启动一个后台任务,在保存时不断将Markdown文件转换为HTML。
  • 因为我们可以将任意JavaScript作为gulp管道的一部分来运行,所以我们应该能够执行额外的工作来操纵生成的HTML,以便博客软件优雅地接受它。
  • 如果编辑体验只是在VS Code中对Markdown文件进行迭代,我们应该能够将这些Markdown文件存储在git中,并使用标准的拉请求审核工作流为out帖子创建审核流程。

解决方案

好,首先我们需要确保我们已经安装了Visual Studio CodeNode.js ,因为它们将成为这个工作流中的主要工具。一旦它们被安装,我们需要创建一个目录,将容纳markdown文件,例如c:\ Blogging ,并打开指向该文件夹的VS Code。

首先在包含以下内容的目录中创建一个空的package.json文件:

{ } 

现在我们需要在文件夹的上下文中运行控制台上的一堆comands,因此通过以下方式打开集成终端:

View => 集成终端

接下来,我们需要全局安装markdown-it,这是我们将用于将Markdown转换为HTML的Node.js包:

npm install -g markdown-it 

接下来,我们需要在全局和本地安装gulp,以及一些gulp扩展,这将有助于管理将markdown文件转换为HTML的工作流程:

npm install -g gulp 
npm install gulp-markdown-it -- 保存

这应该足以让我们写一个gulpfile.js ,将不断转换我们的目录中的Markdown文件转换成HTML,因为他们被保存,并通过一些VS Code魔术Ctrl Shift B启动的过程。

首先,我们将在文件夹中创建一个名为test.md的测试降价文件,并给它一些内容:

# # Introduction
这是一个介绍。

这是另一段。

''cs
// 这是一个门控代码块,
公共类TestClass
{
public void TestMethod()
{

}
}
'''

您可以使用ctrl-k V打开Markdown预览,并在您正在编辑的文件旁边查看预览:

现在,我们可以创建将设置转换工作流的gulp配置。在名为gulpfile.js的目录中创建一个文件,并用以下内容填充它:

vargulp =需要('吞咽');
varmarkdown =需要('大口-降价-它');
varfs =需要('fs');

gulp.task ('降价',功能(){
返回gulp.src(['**/*.md','!node_modules/**'])
。管道 (降价 ({
选项: {
html:
}
}))
。管道 (gulp.De st (功能(f){
返回f.基地;
} ));
});

gulp.task ('默认',['降价'],功能(){
gulp.watch(['**/*.md','!node_modules/**'], ['降价']);
});

保存该文件后,我们应该能够运行gulp并查看结果,因此从集成的终端运行:

gulp 

这会导致在我们的目录中创建一个名为test.html的文件,其中包含以下内容:

< h2 > 介绍 
</ h2 > < p > 这是一个介绍。 </ p >
< p > 这是另一段。 </ p >
< pre > < code class = "language-cs" > // 这是一个门控代码块,
公共类TestClass
{
public void TestMethod()
{

}
}
</ code > </ pre >

按照我们配置的方式,gulp将继续观察此目录 (或子目录) 中Markdown文件的任何更改,如果其中任何更改,它将通过markdown提供这些-它在HTML文件中产生与Markdown文件同名的新html内容。如果我们对Markdown文件进行更改:

# # Introduction
这是一个介绍。

这是另一段。

''cs
// 这是一个门控代码块,
公共类TestClass2
{
public void TestMethod2()
{

}
}
'''

这里, TestClass已更改为读取TestClass2TestMethod已更改为读取TestMethod2。点击保存后,等待片刻,现在test.html包含:

< h2 > 介绍 
</ h2 > < p > 这是一个介绍。 </ p >
< p > 这是另一段。 </ p >
< pre > < code class = "language-cs" > // 这是一个门控代码块,
公共类TestClass2
{
public void TestMethod2()
{

}
}
</ code > </ pre >

这是整洁的,但由于我们使用VS Code,我们甚至可以避免需要运行gulp命令来开始事情。我们需要做的就是创建一个tasks.json文件中的。vscode子文件夹中的项目目录,并提供此内容:

{
"版本":"2.0.0",
"任务": [
{
"类型":"gulp",
"任务":"默认值",
"problemMatcher": [],
"组": {
"种类":"生成",
"isDefault":
}
}
]
}

这使得当您按CTRL SHIFT B时,它将开始在后台运行gulp命令。通过这种方式,我们将VS Code中的markdown编辑器 (包括其非常漂亮的预览窗格) 与Node.js,markdown-it和gulp相结合,以创建一个很棒的HTML编辑器。

驯服Ornery博客引擎

现在,如果你不处理一些ornery博客引擎,就像我们一样,以上可能是你所需要的。但即使这样,你可能会发现这个有趣和有用的休息。以下是我们需要解决的博客引擎的问题:

  • 我们更喜欢将代码片段渲染为静态样式的html,这取决于没有外部JS或CSS样式表。
  • 我们的博客引擎与嵌入的标签混淆标签 (为什么,我不知道)。
  • 我们的博客引擎无法往返换行符在pre标签,经常下降他们,所以它更安全的换行符转换为显式中断标签或事情会搞砸,如果我们重新发布我们的HTML。
  • 我们的博客引擎喜欢破坏空格在开始的行,即使在pre标签,所以我们想将这些转换为非断空格 (& nbsp)

因此,首先,我们将处理突出显示代码片段并在pre标记中清理有问题的HTML。我们将使用一个名为highlightjs的节点包将Markdown中的门控代码博客格式化为一些语法突出显示的标记。所以让我们先安装:

npm install highlightjs -- 保存 

安装后,我们可以将gulpfile.js修改为如下所示:

vargulp =需要('吞咽');
varmarkdown =需要('大口-降价-它');
// 新建
varhljs =需要('highlightjs/highlight.pack.js');
varfs =需要('fs');

// 新建
hljs.configure({
tabReplace:'& nbsp;& nbsp;& nbsp;& nbsp;'
});

gulp.task ('降价',功能(){
返回gulp.src(['**/*.md','!node_modules/**'])
。管道 (降价 ({
选项: {
html:,
// 新建
突出显示:功能(str, lang){
如果(lang & & hljs.getLanguage(lang)) {
试试看{
var输出 = hljs.highlight(lang,str).value;
output = output.replace (/(?:\ r \ n | \ r | \ n)/g,'<br />');
output = output.replace (/^ \ s /gm,功能(m){返回m.更换 (/\ s/g,'& nbsp;');});
output = output.replace (/(\<br \ s \/\>)(\ s )/gm,功能(m){返回m.更换 (/\>(\ s )/g,功能(n){返回n.替换 (/\ s/g,'& nbsp;'); }); });
返回 '<pre class = "hljs"><code>'
输出
'</code></pre>';
}接住(e) {}
}

返回 '';
}
}
}))
。管道 (gulp.De st (功能(f){
返回f.基地;
} ));
});

gulp.task ('默认',['降价'],功能(){
gulp.watch(['**/*.md','!node_modules/**'], ['降价']);
});

在上面我们:

  • 添加一个需要语句,以便我们可以使用highlightjs库。
  • 将highlightjs库配置为使用4个非中断空格而不是制表符字符。
  • 在运行markdown-it时使用突出显示钩子来指定应该如何对围栏代码块执行语法突出显示。在这个例子中,我们调用highlightjs做突出显示。
  • 除了转换围栏代码块之外,我们还对输出内容执行一系列正则表达式替换,以删除对博客引擎有问题的字符模式,并将其替换为等效的更安全的字符序列。

此时应重新启动gulp任务:

F1 => 终止正在运行的任务

然后使用CTRL SHIFT B重新启动任务。在这一点上,你的test.html应该是这样的:

<h2>导言</h2>
<p>这是一个介绍。</p>
<p>这是另一段。</p>
<><代码 ="语言">< ="hljs"><代码><跨距 ="hljs-注释">// 这是一个门控代码块</跨距><br/><跨距 ="hljs-关键字">公共</跨距> <跨距 ="hljs-关键字"></跨距> <跨距 ="hljs-title">TestClass2</跨距><br/>{<br/>& nbsp;& nbsp;& nbsp;& nbsp;<跨距 ="hljs-函数"><跨距 ="hljs-关键字">公共</跨距> <跨距 ="hljs-关键字">无效</跨距> <跨距 ="hljs-title">测试方法2</跨距>(<跨距 ="hljs-params"></跨距>)<br/>& nbsp;& nbsp;& nbsp;& nbsp;</跨距>{<br/>& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;<br/>& nbsp;& nbsp;& nbsp;& nbsp;}<br/>}<br/></代码></></代码></>

它的pretty丑陋的所有换行符从pre标签中删除,但现在应该与博客引擎玩得更好。

在我们称之为完成之前,我们有两个最后的问题要解决。首先,我们希望根据我们网站/营销团队的要求,在新标签页中自动打开所有链接。其次,当前生成的HTML期望加载CSS样式表,以便为代码片段实际着色输出HTML。如果我们在浏览器中查看输出,它看起来像这样:

正如我之前提到的,我们不能将任何per post CSS注入到我们的博客文章中,所以我们宁愿所有的语法着色都直接烘焙到HTML内联中。

值得庆幸的是,对于这两个问题,有一些简单易用的node包来解决问题。首先,我们可以安装一个名为markdown-it-link-target的软件包,它是markdown-it的插件,它将导致链接以在新选项卡中打开的方式呈现:

npm install markdown-it-link-target -- 保存 

接下来,我们将为gulp安装一个插件,它将调用一个名为juice的节点包:

npm install gulp-juice -- save 

juice是一个整洁的库,它将采用CSS样式表和一些HTML,然后将CSS样式烘焙到HTML内联中,以便不再需要外部CSS。要连接这些部分,我们再次需要更新我们的gulpfile,然后重新启动任务:

vargulp =需要('吞咽');
varmarkdown =需要('大口-降价-它');
varhljs =需要('highlightjs/highlight.pack.js');
// 新建
var果汁 =需要('大口果汁');
varfs =需要('fs');

// 新建
varcodeCss = fs.readFileSync ("./node_modules/highlightjs/styles/atom-one-dark.css","utf-8");

hljs.configure({
tabReplace:'& nbsp;& nbsp;& nbsp;& nbsp;'
});
gulp.task ('降价',功能(){
返回gulp.src(['**/*.md','!node_modules/**'])
。管道 (降价 ({
// 新建
插件: ["markdown-it-link-target"],
选项: {
html:,
突出显示:功能(str, lang){
如果(lang & & hljs.getLanguage(lang)) {
试试看{
var输出 = hljs.highlight(lang,str).value;
output = output.replace (/(?:\ r \ n | \ r | \ n)/g,'<br />');
output = output.replace (/^ \ s /gm,功能(m){返回m.更换 (/\ s/g,<span style="color: #98c379;">'& nbsp;');});
output = output.replace (/(\<br \ s \/\>)(\ s )/gm,功能(m){返回m.更换 (/\>(\ s )/g,功能(n){返回n.替换 (/\ s/g,'& nbsp;'); }); });
返回 '<pre class = "hljs"><code>'
输出
'</code></pre>';
}接住(e) {}
}

返回 '';
}
}
}))
// 新建
。管道 (果汁 ({提取: 编解码器}))
。管道 (gulp.De st (功能(f){
返回f.基地;
} ));
});

gulp.task ('默认',['降价'],功能(){
gulp.watch(['**/*.md','!node_modules/**'], ['降价']);
});

有了这些更改, test.html现在应该是这样的:

<h2>导言</h2>
<p>这是一个介绍。</p>
<p>这是另一段。</p>
<><代码 ="语言">< ="hljs" 风格="背景: #282c34; 颜色: # abb2bf; 显示: 块; 溢出-x: 自动; 填充: 0.5em;"><代码><跨距 ="hljs-注释" 风格="颜色: #5c6370; 字体样式: italic;">// 这是一个门控代码块</跨距><br><跨距 ="hljs-关键字" 风格="颜色: # c678dd;">公共</跨距> <跨距 ="hljs-关键字" 风格="颜色: # c678dd;"></跨距> <跨距 ="hljs-title" 风格="颜色: #61aeee;">TestClass2</跨距><br>{<br>& nbsp;& nbsp;& nbsp;& nbsp;<跨距 ="hljs-函数"><跨距 ="hljs-关键字" 风格="颜色: # c678dd;">公共</跨距> <跨距 ="hljs-关键字" 风格="颜色: # c678dd;">无效</跨距> <跨距 ="hljs-title" 风格="颜色: #61aeee;">测试方法2</跨距>(<跨距 ="hljs-params"></跨距</span>>)<br>& nbsp;& nbsp;& nbsp;& nbsp;</跨距>{<br>& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;<br>& nbsp;& nbsp;& nbsp;& nbsp;}<br>}<br></代码></></代码></>

在前面,这一行:

var codeCss = fs.readFileSync( “./node_modules/highlightjs/styles/atom-one-dark.css”“utf-8”; 

加载随highlightjs附带的css文件之一,并将其与HTML一起烘烤。

现在,这可以简单地粘贴为原始HTML到几乎任何支持HTML,包括ornery博客引擎!

如果我们在浏览器中加载它,它看起来像这样:

希望你发现这个有趣和/或有用!

-格雷厄姆 </p