背景
前几天,笔者把项目里的query-string
升级到v6
的版本,为了里面一些新特性(比如,字符串的'1'
转成数字1
)。今天,测试同事和我说,移动端低版本的浏览器跑不起来,我看了报错,发现是编辑完的代码里有箭头函数,心想简单,把query-string
纳入babel的编译范围即可。结果,还是有箭头函数。我又检查了一遍,结果是query-string
的依赖库也有用es6代码写的。
这怎么办?总不能让笔者一个一个把依赖库检查一遍吧。。。。
这是笔者原先的babel-loader配置:
const babelLoader = {
test: /\.(js|jsx|ts|tsx|mjs)$/,
exclude: [/node_modules\/(?![(braft\-editor)|(query\-string)])/, /bower_components/],
include: [paths.appSrc, resolveApp('node_modules/braft-editor'), resolveApp('node_modules/query-string')],
use: ['happypack/loader?id=babel-loader'],
};
怎么处理es6代码写的依赖库?
当然,还是使用babel-loader,但是每次改完 exclude
后,还要去 include
里改,而且可能依赖库的依赖库也有es6的代码,太麻烦了!
笔者之前使用umi
,umi里有个配置字段 nodeModulesTransform
, 可以指定编译node_modules目录下的一些依赖库,使用起来就很便捷。
- 先定义哪些直接的依赖库要单独编译
const nodeModulesTransform = {
type: 'none', // none 不编译node_modules下的;all,编译node_modules下的所有库
exclude: ['braft-editor', 'query-string'],
};
all
的逻辑比较简单,就是编译node_modules下的所有文件,这篇就不讲这部分的实现了,主要讲none
。(下面的都是自己琢磨的,并没有去参考 umi
这部分的实现, 如果有看过 umi
的别杠我 = =)
- 获取依赖库的所有dependencies
由于依赖库的 dependencies
可能也存在 es6 代码,所以宁愿牺牲一点时间,也要用babel把这些dependencies也编译一遍
const path = require('path');
const process = require('process');
function getDeps(moduleName, depMap) {
try {
const modulePkg = require(path.join(process.cwd(), `node_modules/${moduleName}/package.json`));
if(!('dependencies' in modulePkg)) return [];
const dependencies = modulePkg.dependencies;
let deps = [];
for (var key in dependencies) {
if (key in depMap) continue; // 防止有依赖库重复引用或者循环引用,所以加个hash检查下
deps = deps.concat(getDeps(key, depMap));
deps.push(key);
depMap[key] = 1;
}
return deps;
} catch (e) {
console.log(e);
console.log(`${path.join(process.cwd(), `node_modules/${moduleName}/package.json`)} don't exist`);
}
}
- 获取直接依赖库,以及直接依赖库的所有子依赖库
const getAllDeps = (() => {
let deps;
return modules => {
if (deps) return deps;
if (modules.length === 0) return [];
let res = modules.slice();
let depMap = {}; // 依赖库字典
for (var i = 0, len = modules.length; i < len; i++) {
depMap[modules[i]] = 1;
}
for (var i = 0, len = modules.length; i < len; i++) {
res = res.concat(getDeps(modules[i], depMap));
}
res = res.filter(n => {
if (n.indexOf('babel') > -1) return false;
if (['regenerator-runtime', 'core-js', 'promise', 'object-assign', 'setimmediate'].includes(n)) {
return false;
}
return true;
});
deps = res;
return deps;
};
})();
因为最终提供给 babel-loader
的 exclude
和 include
所涉及的第三方模块是相同的,所以笔者使用 闭包 做了一个 缓存代理。
这里获取所有依赖库的方法,是使用的递归,有可能会爆栈。感兴趣的同学可以使用 广度优先搜索 算法来优化上述代码:)
- 提供给
babel-loader
的exclude
和include
function getNodeModulesTransformExclude() {
const modules = getAllDeps(nodeModulesTransform.exclude).map(n => {
return `(${n.replace(/\-/g, '\\-')})`;
});
if (modules.length === 0) {
return /node_modules/;
}
return new RegExp(`node_modules\\/(?![${modules.join('|')}])`);
}
function getNodeModulesTransformInclude() {
return getAllDeps(nodeModulesTransform.exclude).map(n => `node_modules/${n}`);
}
新的 babel-loader
配置如下:
const babelLoader = {
test: /\.(js|jsx|ts|tsx|mjs)$/,
exclude: [getNodeModulesTransformExclude(), /bower_components/],
include: [paths.appSrc, ...getNodeModulesTransformInclude().map(n => resolveApp(n))],
use: ['happypack/loader?id=babel-loader'],
};
以后再遇到某个库使用了es6代码,只需要修改 nodeModulesTransform
中的 exclude
这一处地方即可。
tips: 这几天都在学 Python
, 昨天计划今天讲 Python
的 if
语句,但是这部分内容比较简单, 打算和后面看的 字典 一起讲。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!