资讯专栏INFORMATION COLUMN

构建工具是如何用 node 操作 html/js/css/md 文件的

AZmake / 3245人阅读

摘要:构建工具是如何用操作文件的从本质上来说,源代码文件都是文本文件,文本文件的内容都是字符串,对文本文件的操作其实就是对字符串的操作。在第二种方式中,一般也是将文本解析成一棵抽象语法树,然后进行操作。

构建工具是如何用 node 操作 html/js/css/md 文件的

从本质上来说,html/js/css/md ... 源代码文件都是文本文件,文本文件的内容都是字符串,对文本文件的操作其实就是对字符串的操作。

操作源代码的方式又主要分成两种:

当作字符串,进行增、删、改等操作

按照某种语法、规则,把字符串读取成一个对象,然后对这个对象进行操作,最后导出新的字符串

1. 操作 html 文件

html 的语法比较简单,并且一般操作 html 都是插入、替换、模板引擎渲染等在字符串上的操作,所以使用第一种方式的比较多。

比如:

html-loader

html-webpack-plugin

html-minifier

handlebars 模板引擎

pug 模板引擎

ejs 模板引擎

一般以第二种方式来操作 html 的都是将 html 文本解析成 dom 树对象,然后进行 dom 操作,最后再导出成新的代码文本。

比如:

cheerio

jsdom

parse5

cheerio 为例,操作 html 文本:

cheerio 能够加载一个 html 文本,实例化一个类 jQuery 对象,然后使用 jQueryapi 像操作 dom 一样操作这段文本,最后导出新的 html 文本。

</>复制代码

  1. const cheerio = require("cheerio");
  2. const $ = cheerio.load("

    Hello world

    "); // 加载一个 html 文本
  3. $("h2.title").text("Hello there!");
  4. $("h2").addClass("welcome");
  5. $.html(); // 导出新的 html 文本
  6. //=>

    Hello there!

jsdom 为例,操作 html 文本:

jsdom 是用 js 将一个 html 文本解析为一个 dom 对象,并实现了一系列 web 标准,特别是 WHATWG 组织制定的 DOMHTML 标准。

</>复制代码

  1. const jsdom = require("jsdom");
  2. const { JSDOM } = jsdom;
  3. const dom = new JSDOM(`

    Hello world

    `);
  4. console.log(dom.window.document.querySelector("p").textContent); // "Hello world"
2. 操作 js 文件

因为 js 语法比较复杂,仅仅是如字符串一样进行增删改,只能做一些小的操作,意义不大。所以,一般操作 js 文件都是采用的第二种方式。

在第二种方式中,一般是工具将 js 文本解析成抽象语法树(AST,Abstract Syntax Tree,抽象语法树),然后对这棵语法树以面向对象的方式做增删改等操作,最后再导出成新的代码文本。

生成抽象语法树的工具主要有:

Acorn: 比如 webpack、rollup、UglifyJS 等工具底层都是使用的 acorn 抽象语法树解析器

babel-parser: babel 转码工具底层使用的抽象语法树解析器

acorn 为例,将 1 + 1 片段进行解析:

</>复制代码

  1. const acorn = require("acorn");
  2. const tree = acorn.parse("1 + 1");

</>复制代码

  1. // tree 的 json 化表示
  2. {
  3. type: "Program",
  4. start: 0,
  5. end: 5,
  6. body: [{
  7. type: "ExpressionStatement",
  8. start: 0,
  9. end: 5,
  10. expression: {
  11. type: "BinaryExpression",
  12. start: 0,
  13. end: 5,
  14. left: { type: "Literal", start: 0, end: 1, value: 1, raw: "1" },
  15. operator: "+",
  16. right: { type: "Literal", start: 4, end: 5, value: 1, raw: "1" }
  17. }
  18. }],
  19. sourceType: "script"
  20. }
babel-parser 为例,将 1 + 1 片段进行解析:

</>复制代码

  1. const parser = require("@babel/parser");
  2. const tree = parser.parse("1 + 1");

</>复制代码

  1. // tree 的 json 化表示
  2. {
  3. type: "File",
  4. start: 0,
  5. end: 5,
  6. loc: {
  7. start: { line: 1, column: 0 },
  8. end: { line: 1, column: 5 }
  9. },
  10. program: {
  11. type: "Program",
  12. start: 0,
  13. end: 5,
  14. loc: {
  15. start: { line: 1, column: 0 },
  16. end: { line: 1, column: 5 }
  17. },
  18. sourceType: "script",
  19. interpreter: null,
  20. body: [{
  21. type: "ExpressionStatement",
  22. start: 0,
  23. end: 5,
  24. loc: {
  25. start: { line: 1, column: 0 },
  26. end: { line: 1, column: 5 }
  27. },
  28. expression: {
  29. type: "BinaryExpression",
  30. start: 0,
  31. end: 5,
  32. loc: {
  33. start: { line: 1, column: 0 },
  34. end: { line: 1, column: 5 }
  35. },
  36. left: {
  37. type: "NumericLiteral",
  38. start: 0,
  39. end: 1,
  40. loc: {
  41. start: { line: 1, column: 0 },
  42. end: { line: 1, column: 5 }
  43. },
  44. extra: { rawValue: 1, raw: "1" },
  45. value: 1
  46. },
  47. operator: "+",
  48. right: {
  49. type: "NumericLiteral",
  50. start: 4,
  51. end: 5,
  52. loc: {
  53. start: { line: 1, column: 0 },
  54. end: { line: 1, column: 5 }
  55. },
  56. extra: { rawValue: 1, raw: "1" },
  57. value: 1
  58. }
  59. }
  60. }],
  61. directives: []
  62. },
  63. comments: []
  64. }
3. 操作 css 文件

css 的语法比 html 要复杂一些,一些简单的操作如插入、替换,可以用直接以字符串的方式操作,但如果是压缩、auto prefix、css-modules 等复杂的功能时,就需要用第二种方式操作 css 了。

在第二种方式中,一般也是将 css 文本解析成一棵抽象语法树,然后进行操作。

比如:

postcss: 比如 css-loader、autoprefixer、cssnano 等的底层都是使用的 postcss 来解析

rework、reworkcss: 抽象语法树解析器

csstree: 比如 csso 的底层就是使用 csstree 来解析

postcss 为例,操作 css 文本:

</>复制代码

  1. const autoprefixer = require("autoprefixer");
  2. const postcss = require("postcss");
  3. const precss = require("precss");
  4. const css = `
  5. .hello {
  6. display: flex;
  7. color: red;
  8. backgroundColor: #ffffff;
  9. }
  10. `;
  11. postcss([precss, autoprefixer({browsers: ["last 2 versions", "> 5%"]})])
  12. .process(css)
  13. .then(result => {
  14. console.log(result.css);
  15. });

输出的文本:

</>复制代码

  1. .hello {
  2. display: -webkit-box;
  3. display: -ms-flexbox;
  4. display: flex;
  5. color: red;
  6. backgroundColor: #ffffff;
  7. }
rework 为例,操作 css 文本:

</>复制代码

  1. const css = require("css");
  2. const ast = css.parse("body { font-size: 12px; }");
  3. console.log(css.stringify(ast));

输出的文本:

</>复制代码

  1. body {
  2. font-size: 12px;
  3. }
4. 操作 markdown/md 文件

一般来说,操作 markdown 文本的目的有两个:

作为编辑器编辑 markdown 文本,或作为渲染器渲染 markdown 文本为 html 文本

markdown 文本中读取信息、校验嵌入的源代码、优化格式等

所以,尽管 markdown 的语法也很简单,但一般并不会直接去使用字符串的方式去操作 markdown 文本,一般都是使用的第二种方式。

比如:

markdown-it: 作为编辑器或渲染器的好手

remark: 构建抽象语法树进行操作的好手

markdown-it 为例,操作 markdown 文本:

</>复制代码

  1. const md = require("markdown-it")();
  2. const result = md.render("# markdown-it rulezz!");
  3. console.log(result);

输出的文本:

</>复制代码

  1. markdown-it rulezz!

remark 为例,操作 markdown 文本:

</>复制代码

  1. const remark = require("remark")
  2. const recommended = require("remark-preset-lint-recommended")
  3. const html = require("remark-html")
  4. const report = require("vfile-reporter")
  5. remark()
  6. .use(recommended)
  7. .use(html)
  8. .process("## Hello world!", function(err, file) {
  9. console.error(report(err || file))
  10. console.log(String(file))
  11. })

校验错误提示:

</>复制代码

  1. 1:1 warning Missing newline character at end of file final-newline remark-lint
  2. ⚠ 1 warning

输出的文本:

</>复制代码

  1. Hello world!

后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99010.html

相关文章

  • 构建工具是如何用 node 操作 html/js/css/md 文件

    摘要:构建工具是如何用操作文件的从本质上来说,源代码文件都是文本文件,文本文件的内容都是字符串,对文本文件的操作其实就是对字符串的操作。在第二种方式中,一般也是将文本解析成一棵抽象语法树,然后进行操作。 构建工具是如何用 node 操作 html/js/css/md 文件的 从本质上来说,html/js/css/md ... 源代码文件都是文本文件,文本文件的内容都是字符串,对文本文件的操作...

    PingCAP 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<