webpack(三)-基础实现

167 阅读1分钟

文件打包

(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;