webpack处理文件内容——babel插件保姆级教学

2020-10-30  本文已影响0人  景阳冈大虫在此

此篇为webpack处理文件内容——编写postcss8.0插件姐妹篇

本文目标

探究编写一个babel插件,将代码里的http:转成https:

前言

webpack的babel原理好多博客都有讲,Babel 插件手册里面说

Babel 的三个主要处理步骤分别是:解析(parse),转换(transform),生成(generate)

解析步骤接收代码并输出 AST。 这个步骤分为两个阶段:词法分析(Lexical Analysis)语法分析(Syntactic Analysis)

转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。

代码生成步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建源码映射(source maps)

其实就是code->AST->对AST操作->生成code

那么问题来了,如何对AST进行操作?

AST

用这个网站可以将代码转成AST:https://astexplorer.net/

const AURL = 'http://XXXXX';
const BURL = 'http://XX.XXX';
function jump(path) {
    window.location.href = path;
}
jump(AURL);
window.location.href = 'http://XXXXX';

开始写插件

Visitors访问者

写一个自己的插件之前,还记得怎么给babel使用插件吗?来复习一下吧。假设我们的插件即将放在根目录的plugins文件夹里,叫tran-http-plugin

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
      }
    }
  ]
}
 "plugins": ["plugins/tran-http-plugin"]
module.exports = function ({ types: t }) {
    return {
        visitor: {
            Identifier(path) {
                console.log('Visiting: ' + path.node.name);
            },
            VariableDeclaration(path, state) {
                console.log('VariableDeclaration');
            },
        },
    };
};

改变节点

在上一个环节我们找到了想改的内容


关键点
思路

建一个一样的节点,然后替换他!

构建节点

这里我们用到的是@babel/types 插件,各种节点的说明文档在此
这个文档反正挺惜字如金的

以这个赋值语句为例分析

const AURL = 'http://XXXXX';
  1. 如何快速定位?变量声明节点的构成是什么?
    如果打开文档,就会发现节点多得数不清,完全不晓得我们要从哪里下手去构建这个声明语句的node。

在写代码之前,我们先了解一下赋值语句的语法节点构成吧。

对于赋值语句,可以从断点的那个path看出关键词。搜一下declarations这个单词,有且只有两个相关节点。

variableDeclaration:t.variableDeclaration(kind, declarations)
variableDeclarator:t.variableDeclarator(id, init)

得出推论
a. 一个变量声明语句节点为variableDeclaration,kind为这个变量的类型,var、const这种,declarations是一个数组(Array<VariableDeclarator>)。
b. 每一个VariableDeclarator拥有自己的id和init属性。从调试结果来看,在这个赋值语句中,id就是Identifier节点,init是StringLiteral节点。

综上,一个赋值语句的语法树会出现variableDeclarationVariableDeclaratorIdentifierStringLiteral这四种节点。
————————
赋值语句节点伪代码如下

variableDeclaration(kind,[
    VariableDeclarator(Identifier,StringLiteral)
])
  1. 怎么写
    我们要操作的其实是stringLiteral,这里是等号右边那个值。把这个字符串替换掉。
    在上面的截图里也有体现了,完整代码如下
// tran-http-plugin.js
module.exports = function ({ types: t }) {
    return {
        visitor: {
            Identifier(path) {
                console.log('Visiting: ' + path.node.name);
            },
            StringLiteral(path) {
                var node = path.node;
                var oldVal = node.value;
                var matchRes = oldVal.match(/http:\/\/([\w.]+\/?)\S*/);
                var newVal = '';
                if (!matchRes) return;
                newVal = oldVal.replace(/http:\/\//g, 'https://');
                path.replaceWith(t.StringLiteral(newVal));
            },
        },
    };
};
  1. 打包结果
const AURL = 'http://XXXXX';
const BURL = 'http://XX.XXX';
function jump(path) {
    window.location.href = path;
}
jump(AURL);
window.location.href = 'http://XXXXX';

参考资料:
babel脚本文档
https://zhuanlan.zhihu.com/p/84799735
https://www.jianshu.com/p/7c8c5ae1e4be
https://www.csdn.net/gather_2b/MtTacg0sMzQwNzYtYmxvZwO0O0OO0O0O.html
https://www.jianshu.com/p/44c0075fd043

上一篇下一篇

猜你喜欢

热点阅读