文件打包
(function(modules){
var installedModules = {};
function _webpack_require_(moduleId){
if(installedModule[moduleId]){
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports,)
module.l = true;
return module.exports;
}
return _webpack_require_(_webpack_require_.s = './src/index.js');
})()
//更改package.json
{
"bin": {
"start": "./bin/start.js"
}
}
//start.js
#! /usr/bin/env node //声明执行环境
console.log(start);
//
let path = require('path');
let config = require(path.resolve(_dirname));
let Compiler = require('../lib/Compiler.js');
let compiler = new Compiler(config);
//运行
compoler.run();
let fs = require('fs');
let path = require('path');
let babylon = require('babylon');// babybon 主要把源码转换成AST
let traverse = require('@babel/traverse').default;
let t = require('@babel/types');
let generator = require('@babel/generator').default;
class Compiler{
constructor(config){
this.config = config;
this.entryId;
this.modules = {};
this.entry = config.entry;
this.rootDir = process.cwd();//当前工作路径
}
parse(source, parenthPath){ //AST解析语法树
let ast = babylon.parse(source);
let dependencies = [];
traverse(ast, {
CallExpresssion(p){
let node = p.node;
if(node.callee.name === 'require'){
node.callee.name = '_webpack_require_';
let moduleName = node.arguments[0].value; // 模块名字
moduleName = moduleName + (path.extname(moduleName)?'':'.js');
moduleName = './' + path.join(parenthPath, moduleName);
dependencies.push(moduleName);
node.arguments = [t.stringLiteral(moduleName)];
}
}
});
let sourceCode = generator(ast).code;
return { sourceCode, dependencies}
}
buildModule(modulePath, isEntry){
//拿到模块内容
let source = this.getSource(modulePath, 'utf8');
//拿到模块id
let moduleName = './'+path.relative(this.root, modulePath);
if(isEntry){
this.entryId = moduleName; //保存入口的id
}
// 解析source源码进行改造, 返回一个依赖列表
let {sourceCode, dependencies} = this.parse(source,path.dirname(moduleName));
this.modules[moduleName] = sourceCode;
dependencies.forEach(dep => {
this.buildModule(path.join(this.rootPath, dep), false);
});
}
getSource(){
let rules = this.config.module.rules;
for(let i = 0; i< rules.length; i++){
let rule = rules[i];
let {test,use} = rule;
let len = rule.length -1;
if(test.test(modulePath)){
function normalLoader(){
let loader = rquire(use[len--]);
loader(content)
if(len>=0){
normalLoader()
}
}
normalLoader()
}
}
}
emitFile(){ //发射文件
//用数据渲染我们的
let main = path.join(this.config.output.path, this.config.output.filename);
let templateStr = this.getSource(path.join(__dirname, 'main.ejs'));
let code = ejs.render(templateStr, {entryId: this.entryId, modules: this.modules});
this.assets = {};
this.assets[main] = code;
fs.writeFileSync(main, code);
}
run(){
// 执行 并且创建模块的依赖关系
this.buildModule(path.resolve(this.root, this.entry), true);
//发射一个文件 打包后的文件
this.emitFile();
}
}
module.exports = Compiler;
npm link //链接 当前link到全局
npm link start
全局的包映射到本地
npm start
loader
let less = require('less');
function loader(source){
let css = '';
less.rnder(source, funtcion(err,c){
css = c.css;
});
return css;
}
module.exports = loader;
function loader(source){
let style = `
let style = document.createElement('style');
style.innerHTML = ${JSON.stringify(source)};
document.head.appendChild(style);
`
return style;
}
module.exports = loader;