zoukankan      html  css  js  c++  java
  • 构建工具是如何用 node 操作 html/js/css/md 文件的

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

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

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

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

    1. 操作 html 文件

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

    比如:

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

    比如:

    cheerio 为例,操作 html 文本:

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

    const cheerio = require('cheerio');
    const $ = cheerio.load('<h2 class="title">Hello world</h2>'); // 加载一个 html 文本
    
    $('h2.title').text('Hello there!');
    $('h2').addClass('welcome');
    
    $.html(); // 导出新的 html 文本
    //=> <h2 class="title welcome">Hello there!</h2>
    

    jsdom 为例,操作 html 文本:

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

    const jsdom = require("jsdom");
    const { JSDOM } = jsdom;
    
    const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
    console.log(dom.window.document.querySelector("p").textContent); // "Hello world"
    

    2. 操作 js 文件

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

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

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

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

    const acorn = require('acorn');
    
    const tree = acorn.parse('1 + 1');
    
    // tree 的 json 化表示
    {
      type: 'Program',
      start: 0,
      end: 5,
      body: [{
        type: 'ExpressionStatement',
        start: 0,
        end: 5,
        expression: {
          type: 'BinaryExpression',
          start: 0,
          end: 5,
          left: { type: 'Literal', start: 0, end: 1, value: 1, raw: '1' },
          operator: '+',
          right: { type: 'Literal', start: 4, end: 5, value: 1, raw: '1' } 
        }
      }],
      sourceType: 'script' 
    }
    

    babel-parser 为例,将 1 + 1 片段进行解析:

    const parser = require('@babel/parser');
    
    const tree = parser.parse('1 + 1');
    
    // tree 的 json 化表示
    {
      type: 'File',
      start: 0,
      end: 5,
      loc: {
        start: { line: 1, column: 0 },
        end: { line: 1, column: 5 } 
      },
      program: {
        type: 'Program',
        start: 0,
        end: 5,
        loc: {
          start: { line: 1, column: 0 },
          end: { line: 1, column: 5 } 
        },
        sourceType: 'script',
        interpreter: null,
        body: [{
          type: 'ExpressionStatement',
          start: 0,
          end: 5,
          loc: {
            start: { line: 1, column: 0 },
            end: { line: 1, column: 5 } 
          },
          expression: {
            type: 'BinaryExpression',
            start: 0,
            end: 5,
            loc: {
              start: { line: 1, column: 0 },
              end: { line: 1, column: 5 } 
            },
            left: {
              type: 'NumericLiteral',
              start: 0,
              end: 1,
              loc: {
                start: { line: 1, column: 0 },
                end: { line: 1, column: 5 } 
              },
              extra: { rawValue: 1, raw: '1' },
              value: 1        
            },
            operator: '+',
            right: {
              type: 'NumericLiteral',
              start: 4,
              end: 5,
              loc: {
                start: { line: 1, column: 0 },
                end: { line: 1, column: 5 } 
              },
              extra: { rawValue: 1, raw: '1' },
              value: 1 
            } 
          } 
        }],
        directives: [] 
      },
      comments: [] 
    }
    

    3. 操作 css 文件

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

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

    比如:

    postcss 为例,操作 css 文本:

    const autoprefixer = require('autoprefixer');
    const postcss = require('postcss');
    const precss = require('precss');
    
    const css = `
    .hello {
      display: flex;
      color: red;
      backgroundColor: #ffffff;
    }
    `;
    
    postcss([precss, autoprefixer({browsers: ['last 2 versions', '> 5%']})])
      .process(css)
      .then(result => {
        console.log(result.css);
      });
    

    输出的文本:

    .hello {
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      color: red;
      backgroundColor: #ffffff;
    }
    

    rework 为例,操作 css 文本:

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

    输出的文本:

    body {
      font-size: 12px;
    }
    

    4. 操作 markdown/md 文件

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

    1. 作为编辑器编辑 markdown 文本,或作为渲染器渲染 markdown 文本为 html 文本
    2. markdown 文本中读取信息、校验嵌入的源代码、优化格式等

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

    比如:

    • markdown-it: 作为编辑器或渲染器的好手
    • remark: 构建抽象语法树进行操作的好手

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

    const md = require('markdown-it')();
    const result = md.render('# markdown-it rulezz!');
    
    console.log(result);
    

    输出的文本:

    <h1>markdown-it rulezz!</h1>
    

    remark 为例,操作 markdown 文本:

    const remark = require('remark')
    const recommended = require('remark-preset-lint-recommended')
    const html = require('remark-html')
    const report = require('vfile-reporter')
    
    remark()
      .use(recommended)
      .use(html)
      .process('## Hello world!', function(err, file) {
        console.error(report(err || file))
        console.log(String(file))
      })
    

    校验错误提示:

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

    输出的文本:

    <h2>Hello world!</h2>
    

    后续

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

    作者:深予之 (@senntyou)

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

  • 相关阅读:
    《Python自动化运维:技术与最佳实践》
    舍本求末的运维自动化技术热潮
    Policy Gradients
    Machine Learning Notes Ⅵ
    Machine Learning Notes Ⅴ
    Machine Learning Notes Ⅳ
    Machine Learning Notes Ⅲ
    Machine Learning Notes Ⅱ
    Machine Learning Notes Ⅰ
    在Linux系统中如何把文件拷贝到U盘
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9916197.html
Copyright © 2011-2022 走看看