<script src="./a.js"></script>
<script src="./b.js"></script>
<script>
console.log('a==>>', a);
console.log('b==>>', b);
</script>
// index.js
const { a } = require('./a.js');
const { b } = require('./b.js');
console.log('a==>>', a);
console.log('b==>>',b);
// a.js
exports.a = 'a';
// b.js
console.log('in b')
exports.b = 'b'
既然 node 有现成模块化方案,就按 node 的规范来吧。开发时按照上边 node 规范写代码,通过一个工具把生成的文件输出到一个大文件夹即可,需要解决的问题如下:
页面开发时使用 node
的模块化规范
开发完成后使用 node工具
把代码修改成符合浏览器运行规范的代码
module
对象里维护module
内的文件进行打包require
方法const modules = {
0: (require, exports) => {
const { a } = require('./a.js');
const { b } = require('./b.js');
console.log('a==>>', a);
console.log('b==>>', b);
},
1: (require, exports) => {
exports.a = 'a';
},
2: (require, exports) => {
console.log('in b');
exports.b = 'b';
},
};
module
内的文件进行打包function build(moduleId) {
const exports = {};
const fn = modules[moduleId];
fn(require, exports);
function require(path) {
// 实现 require 方法即可
}
return exports;
}
build(0);
require
方法
modules
数据里加上每个模块依赖的模块吧const modules = {
0: [
(require, exports) => {
const { a } = require('./a.js');
const { b } = require('./b.js');
console.log('a==>>', a);
console.log('b==>>', b);
},
{ './a.js': 1, './b.js': 2 },
],
1: [
(require, exports) => {
exports.a = 'a';
},
{},
],
2: [
(require, exports) => {
console.log('in b');
exports.b = 'b';
},
{},
],
};
function build(moduleId) {
const exports = {};
let [fn, map] = modules[moduleId];
fn && fn(require, exports);
function require(path) {
// 根据 path 获取 modules 里对应模块的代码
return build(map[path]);
}
return exports;
}
build(0);
modules
的格式const modules = {
0: [
(require, exports) => {
const { a } = require('./a.js');
const { b } = require('./b.js');
console.log('a==>>', a);
console.log('b==>>', b);
},
{ './a.js': 1, './b.js': 2 },
],
1: [
(require, exports) => {
exports.a = 'a';
},
{},
],
2: [
(require, exports) => {
console.log('in b');
exports.b = 'b';
},
{},
],
};
// 获取文件依赖
function getDependencies(code) {
// return ['./a.js', './b.js'];
}
// 获取文件依赖
function getDependencies(code) {
// 此处使用用正则获取依赖
let reg = /require\(['"](.+?)['"]\)/g;
let result = null;
const dependencies = [];
while ((result = reg.exec(code))) {
dependencies.push(result[1]);
}
return dependencies;
}
function createAssets(fileName) {
// return {
// id: 0,
// dependency: ['./a.js', './b.js'],
// code: (require, exports) => {
// const { a } = require('./a.js');
// const { b } = require('./b.js');
// console.log('a==>>', a);
// console.log('b==>>', b);
// },
// };
}
// 记录模块 id
let ID = 0;
// 生成单个文件数据对象
function createAssets(fileName) {
const fileContent = fs.readFileSync(fileName, 'utf-8');
return {
id: ID++,
fileName,
dependency: getDependencies(fileContent),
code: `function (require, exports) {${fileContent}}`,
};
}
// 生成所有模块
function createQueue() {
// return [
// {
// path: './index.js',
// id: 0,
// dependency: ['./a.js', './b.js'],
// code: (require, exports) => {
// const { a } = require('./a.js');
// const { b } = require('./b.js');
// console.log('a==>>', a);
// console.log('b==>>', b);
// },
// },
// {
// path: './a.js',
// id: 1,
// dependency: [],
// code: (require, exports) => {
// exports.a = 'a';
// },
// },
// ];
}
// 生成所有模块
function createQueue(fileName) {
const asset = createAssets(fileName);
const queue = [asset];
// 使用 let of 在循环过程中,数组增加的内容依然会被遍历
for (let asset of queue) {
const dirname = path.dirname(asset.fileName);
asset.map = {};
asset.dependency.forEach((relativePath) => {
// 此处使用绝对路径,避免报错
const absolutePath = path.join(dirname, relativePath);
// 获取被依赖模块
const model = createAssets(absolutePath);
// 在当前模块的依赖 map 中加上这个模块
asset.map[relativePath] = model.id;
// 放到模块数组放到队列中
queue.push(model);
});
}
return queue;
}
const result = createQueue('./entry.js');
// 写入打包文件
function createBundle(queue) {
// fs.writeFileSync('./dist/bundle.js', result);
}
function createBundle(result) {
let modules = ``;
result.forEach((item) => {
modules += `${item.id}:[${item.code}, ${JSON.stringify(item.map)}],`;
});
const fileContent = `(function (modules) {
function build(id) {
const [fn, map] = modules[id];
const exports = {};
fn && fn(require, exports);
function require(path) {
return build(map[path]);
}
return exports;
}
build(0);
})({${modules}})`;
fs.writeFileSync('./bundle.js', fileContent);
// fs.writeFileSync('./dist/bundle.js', result);
}
createBundle(result)
如果您有任何问题、建议或合作意向,欢迎通过此表单与我联系。我会尽快回复您的留言。