10-自定义打包工具

nobility 发布于 2022-01-15 1208 次阅读


自定义打包工具

使用babel工具对js文件做语法解析,从而将多个js文件模块打包成一个文件

  1. 使用npm install @babel/parser安装js语法解析工具
  2. 使用npm install @babel/traverse安装对解析后的js语法进行过滤工具
  3. 使用npm install @babel/core @babel/preset-env安装将es6翻译成es5工具
const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default; //兼容es6模块化导出
const babel = require("@babel/core");

/**
 * 根据入口文件生成依赖映射
 * @param {*} entry 入口文件
 */
function dependenceMap(entry) {
	/**
	 * 将单个文件依赖以对象形式返回(路径形式)
	 * @param {*} entry 入口文件
	 * 当前返回的对象中的依赖是{相对路径:绝对路径}
	 */
	function moduleAnalysis(entry) {
		const dependence = {}; //依赖对象
		const content = fs.readFileSync(entry, "utf-8"); //读取文件内容
		const ast = parser.parse(content, { //将文件内容解析成抽象语法树
			sourceType: "module" //以es6模块化解析
		});
		const { code } = babel.transformFromAst(ast, null, { //将抽象语法树翻译成es5代码
			presets: ["@babel/preset-env"]
		})
		const dirname = path.dirname(entry); //获取入口文件目录的相对路径
		traverse(ast, {
			ImportDeclaration({ node }) { //过滤出es6模块导入语句    
				const relativePath = node.source.value
				dependence[relativePath] = path.join(dirname, relativePath); //将依赖文件存储到依赖对象中
			}
		});
		return {
			code, //编译成es5的代码
			dependence, //依赖对象
			entry //入口文件
		}
	}
	const rootModule = moduleAnalysis(entry)
	/**
	 * 将以moduleRoot为根的返回的依赖对象进行路径和内容之间的转化
	 * @param {*} rootModule 以该对象为根的依赖对象
	 * 处理后的对象中的依赖是{相对路径:具体内容}
	 */
	function replacePath(rootModule) {
		key = Object.keys(rootModule.dependence); //获取模块对象的依赖对象的key
		key.forEach(item => { //根据key遍历模块对象的依赖对象
			const drelativePath = rootModule.dependence[item]; //获取依赖文件的绝对路径
			const moduleObj = moduleAnalysis(drelativePath); //根据依赖的绝对路径转化成模块对象
			rootModule.dependence[item] = moduleObj; //将模块对象替换掉原来的路径
			replacePath(moduleObj); //以替换掉的模块对象为根递归调用,直到整棵树中的路径都替换为对象
		});
	}
	replacePath(rootModule);

	const map = {
		[entry]: rootModule.code
	};
	/**
	 * 将树状依赖对象拉平放入到map中,调用一次拉平一层
	 * @param {*} obj 要拉平的对象
	 */
	function flot(obj) {
		if (!obj.dependence) return;
		const keys = Object.keys(obj.dependence);
		keys.forEach(item => {
			map[item] = obj.dependence[item].code;  //map存放{入口:代码}对象
			flot(obj.dependence[item]); //依赖对象递归调用
		})
	}
	flot(rootModule);
	return map;
}
/**
 * 根据入口文件生成浏览器可执行代码
 * @param {*} entry 入口文件
 */
function generateCode(entry) {
	const map = dependenceMap(entry);
	const code = `
	(function (map) {
		function require(module) {
			var exports = {};	//导出对象,否则无法导出
			(function (exports, code) { eval(code); })(exports, map[module]);
			return exports;
		};
		require("${entry}");
	})(${JSON.stringify(map)})
	`
	return code
}

const code = generateCode("index.js");
fs.writeFileSync("./dist/main.js", code);
此作者没有提供个人介绍
最后更新于 2022-01-15