2018-09-29

Webpack流程概括


  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数; 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;

  • 确定入口:根据配置中的 entry 找出所有的入口文件;

  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;

  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;

  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;

  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

    在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

2. 钩子 [#](#t12. 钩子)

  • entryOption
  • afterPlugins
  • run
  • compile
  • afterCompile
  • emit
  • done

3. 编写webpack [#](#t23. 编写webpack)

调试执行webpack

npm link

3.1 创建项目 [#](#t33.1 创建项目)

"bin": {"zxmfpack": "./bin/zxmfpack.js"}

3.2 创建可执行文件 [#](#t43.2 创建可执行文件)

#! /usr/bin/env node
const path=require('path');
const fs=require('fs');
const Compiler=require('../lib/Compiler');
let root=process.cwd();
let options=require(path.resolve(root,'webpack.config.js'));
let compier=new Compiler(options);
compier.hooks.entryOption.call(options);
compier.run();

3.3 创建Compiler对象 [#](#t53.3 创建Compiler对象)

const {SyncHook}=require('tapable');
const path=require('path');
const fs=require('fs');
const babylon = require('babylon')
const t = require('@babel/types')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const ejs=require('ejs');
class Compiler{
    constructor(options) {
        this.options=options;
        this.hooks={
            entryOption: new SyncHook(['options']),
            afterPlugins: new SyncHook(),
            run: new SyncHook(),
            compile: new SyncHook(),
            afterCompile: new SyncHook(),
            emit: new SyncHook(),
            done:new SyncHook()
        }
        let plugins=options.plugins;
        if (plugins&&plugins.length>0) {
            plugins.forEach(plugin=>plugin.apply(this));
        }
        this.hooks.afterPlugins.call();
    }
}

3.4 开始编译 [#](#t63.4 开始编译)

const {SyncHook}=require('tapable');
const path=require('path');
const fs=require('fs');
const babylon = require('babylon')
const t = require('@babel/types')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const ejs=require('ejs');
class Compiler{
    constructor(options) {
        this.options=options;
        this.hooks={
            entryOption: new SyncHook(['options']),
            afterPlugins: new SyncHook(),
            run: new SyncHook(),
            compile: new SyncHook(),
            afterCompile: new SyncHook(),
            emit: new SyncHook(),
            done:new SyncHook()
        }
        let plugins=options.plugins;
        if (plugins&&plugins.length>0) {
            plugins.forEach(plugin=>plugin.apply(this));
        }
        this.hooks.afterPlugins.call();
    }
    run() {
        let compiler=this;
        this.hooks.run.call(compiler);
        this.root=process.cwd();
        let {entry}=this.options;
        this.modules={};//存放所有的模块
        this.entryId;//入口文件ID,所有的ID都是相对于根目录的
        this.hooks.compile.call(compiler);

        this.buildModule(path.resolve(this.root,entry),true);//解析入口模块

        this.hooks.afterCompile.call(compiler);
        this.emitFile();
    }
    emitFile() {
        this.hooks.emit.call(this);
        let mainTemplate=fs.readFileSync(path.join(__dirname,'main.ejs'),'utf8');
        let {modules,entryId}=this;
        let main=ejs.compile(mainTemplate)({modules,entryId});
        let {output: {path: dist,filename}}=this.options;
        fs.writeFileSync(path.join(dist,filename),main);
        this.hooks.done.call(this);
    }

    buildModule(modulePath,isEntry) {//解析模块和依赖的模块 路径是一个绝对路径
        let source=this.runLoaders(modulePath);      //获取源代码
        let moduleId='./'+path.relative(this.root,modulePath); //获取相对路径,因为所有的模块ID都是以项目根目录开始的
        if (isEntry) this.entryId=moduleId;
        let result=this.parse(source,path.dirname(moduleId));//获取AST解析结果
        let dependencies=result.dependencies;//获取次模块依赖的其它模块
        this.modules[moduleId]=result.source;//记录一下模块ID和转换后的代码对应关系
        dependencies.forEach(dependency=>this.buildModule(path.join(this.root,dependency)));
    }

    resolveModule(module) {
        return path.resolve(this.root,'node_modules',module)
    }

    runLoaders(modulePath) {
        let {module:{rules}}=this.options;
        let source=fs.readFileSync(modulePath,'utf8');
        console.log('source1',modulePath,source);
        for (let i=0;i<rules.length;i++){
            let rule=rules[i];
            if (rule.test.test(modulePath)) {
                let use=rule.use||rule.loader;
                if (Array.isArray(use)) {
                    let loaderIndex=use.length-1;
                    let  iterateLoaders = () => {
                        if (loaderIndex<0)return;
                        let currentLoader=require(this.resolveModule(use[loaderIndex--]));
                        source=currentLoader(source);
                        iterateLoaders();
                    }
                    iterateLoaders();
                } else {
                    let loader=require(this.resolveModule(typeof use=='string'? use:use.loader));
                    source=loader(source);
                }
                break;
            }
        }
        console.log('source2',source);
        return source;
    }

    //参数为源代码和父路径
    parse(source,parentPath) {
        let compiler=this;
        const ast=babylon.parse(source,{
            plugins:['dynamicImport']
        })
        let dependencies=[];
        traverse(ast,{
            CallExpression(p) {
                if (p.node.callee.name=='require') {
                    let node=p.node;
                    node.callee.name='__webpack_require__';
                    let name=node.arguments[0].value;//取得参数里面的值
                    name += (name.lastIndexOf('.')>0? '':'.js');// 添加.js后缀
                    let moduleId='./'+path.join(parentPath,name);//取得此模块ID,也是相对于根路径的
                    dependencies.push(moduleId);
                    node.arguments=[t.stringLiteral(moduleId)];
                }
            }
        });
        source=generate(ast).code;
        return {source,dependencies};
    }
}

module.exports=Compiler;

main.ejs

/******/ (function(modules) { // webpackBootstrap
    /******/     // The module cache
    /******/     var installedModules = {};
    /******/
    /******/     // The __webpack_require__ function
    /******/     function __webpack_require__(moduleId) {
    /******/
    /******/         // Check if module is in cache
    /******/         if(installedModules[moduleId]) {
    /******/             return installedModules[moduleId].exports;
    /******/         }
    /******/         // Create a new module (and put it into the cache)
    /******/         var module = installedModules[moduleId] = {
    /******/             i: moduleId,
    /******/             l: false,
    /******/             exports: {}
    /******/         };
    /******/
    /******/         // Execute the module function
    /******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    /******/
    /******/         // Flag the module as loaded
    /******/         module.l = true;
    /******/
    /******/         // Return the exports of the module
    /******/         return module.exports;
    /******/     }
    /******/     // Load entry module and return exports
    /******/     return __webpack_require__(__webpack_require__.s = "<%-entryId%>");
    /******/ })
    /************************************************************************/
    /******/ ({
    <%
    for(let id in modules){
        let source = modules[id];%>
    /***/ "<%-id%>":
    /***/ function(module, exports,__webpack_require__) {

    eval(`<%-source%>`);

    /***/ },
    <%}%>
    /******/ });

3.5 产出文件 [#](#t73.5 产出文件)

3.5.1 src/index.js [#](#t83.5.1 src/index.js)

let a1=require('./a1');
console.log(a1);

3.5.2 src/a1.js [#](#t93.5.2 src/a1.js)

let a2=require('./base/a2');
module.exports='a1'+a2;

3.5.3 src/base/a2.js [#](#t103.5.3 src/base/a2.js)

module.exports='a2';

3.5.4 bundle.js [#](#t113.5.4 bundle.js)

/******/ (function(modules) { // webpackBootstrap
    /******/     // The module cache
    /******/     var installedModules = {};
    /******/
    /******/     // The require function
    /******/     function __webpack_require__(moduleId) {
    /******/
    /******/         // Check if module is in cache
    /******/         if(installedModules[moduleId]) {
    /******/             return installedModules[moduleId].exports;
    /******/         }
    /******/         // Create a new module (and put it into the cache)
    /******/         var module = installedModules[moduleId] = {
    /******/             i: moduleId,
    /******/             l: false,
    /******/             exports: {}
    /******/         };
    /******/
    /******/         // Execute the module function
    /******/         modules[moduleId].call(module.exports, module, module.exports, require);
    /******/
    /******/         // Flag the module as loaded
    /******/         module.l = true;
    /******/
    /******/         // Return the exports of the module
    /******/         return module.exports;
    /******/     }
    /******/     // Load entry module and return exports
    /******/     return __webpack_require__(require.s = "./src/index.js");
    /******/ })
    /************************************************************************/
    /******/ ({

    /***/ "./src/index.js":
    /***/ function(module, exports,__webpack_require__) {

    eval(`let a1 = __webpack_require__('./src/a1.js');
console.log(a1);`);

    /***/ },

    /***/ "./src/a1.js":
    /***/ function(module, exports,__webpack_require__) {

    eval(`let a2 = __webpack_require__('./src/base/a2.js');
module.exports = 'a1' + a2;`);

    /***/ },

    /***/ "./src/base/a2.js":
    /***/ function(module, exports,__webpack_require__) {

    eval(`module.exports = 'a2';`);

    /***/ },

    /******/ });

3.6 支持loader [#](#t123.6 支持loader)

3.6.1 less-loader [#](#t133.6.1 less-loader)

var less = require('less');
module.exports = function (source) {
    let css;
    less.render(source, (err, output) => {
        css = output.css;
    });
    return css.replace(/\n/g,'\\n','g');
}

3.6.2 style-loader [#](#t143.6.2 style-loader)

module.exports = function (source) {
    let str = `
      let style = document.createElement('style');
      style.innerHTML = ${JSON.stringify(source)};
      document.head.appendChild(style);
    `;
    return str;
}

3.6.3 webpack.config.js [#](#t153.6.3 webpack.config.js)

module: {
        rules: [
            {
                test: /\.less$/,
                use:['css-loader','less-loader']
            }
        ]
    },

3.7 支持插件 [#](#t163.7 支持插件)

const path=require('path');

class EntryOptionWebpackPlugin{
    apply(compiler) {
        compiler.hooks.entryOption.tap('Plugin',(option) => {
            console.log('EntryOptionWebpackPlugin');
        });
    }
}

class AfterPlugins{
    apply(compiler) {
        compiler.hooks.afterPlugins.tap('Plugin',(option) => {
            console.log('AfterPlugins');
        });
    }
}

class RunPlugin{
    apply(compiler) {
        compiler.hooks.run.tap('Plugin',(option) => {
            console.log('RunPlugin');
        });
    }
}

class CompileWebpackPlugin{
    apply(compiler) {
        compiler.hooks.compile.tap('Plugin',(option) => {
            console.log('CompileWebpackPlugin');
        });
    }
}

class AfterCompileWebpackPlugin{
    apply(compiler) {
        compiler.hooks.afterCompile.tap('Plugin',(option) => {
            console.log('AfterCompileWebpackPlugin');
        });
    }
}
class EmitWebpackPlugin{
    apply(compiler) {
        compiler.hooks.emit.tap('Plugin',(option) => {
            console.log('EmitWebpackPlugin');
        });
    }
}
class DoneWebpackPlugin{
    apply(compiler) {
        compiler.hooks.done.tap('Plugin',(option) => {
            console.log('DoneWebpackPlugin');
        });
    }
}
module.exports={
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname,'dist'),
        filename:'bundle.js'
    },
    resolveLoader: {
        modules: [path.resolve(__dirname,'node_modules'),
        path.resolve(__dirname,'src','loaders')]
    },
    module: {
        rules: [
            {
                test: /\.less$/,
                use:['css-loader','less-loader']
            }
        ]
    },
    plugins: [
        new EntryOptionWebpackPlugin(),
        new AfterPlugins(),
        new RunPlugin(),
        new CompileWebpackPlugin(),
        new AfterCompileWebpackPlugin(),
        new EmitWebpackPlugin(),
        new DoneWebpackPlugin()
    ]
}

3.8 支持懒加载 [#](#t173.8 支持懒加载)

3.8.1 Compiler [#](#t183.8.1 Compiler)

const {SyncHook}=require('tapable');
const path=require('path');
const fs=require('fs');
const babylon = require('babylon')
const t = require('@babel/types')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const ejs=require('ejs');
class Compiler{
    constructor(options) {
        this.options=options;
        this.hooks={
            entryOption: new SyncHook(['options']),
            afterPlugins: new SyncHook(),
            run: new SyncHook(),
            compile: new SyncHook(),
            afterCompile: new SyncHook(),
            emit: new SyncHook(),
            done:new SyncHook()
        }
        let plugins=options.plugins;
        if (plugins&&plugins.length>0) {
            plugins.forEach(plugin=>plugin.apply(this));
        }
        this.hooks.afterPlugins.call();
        this.chunks={};
        this.chunkIndex=0;
    }
    run() {
        let compiler=this;
        this.hooks.run.call(compiler);
        this.root=process.cwd();
        let {entry}=this.options;
        this.modules={};//存放所有的模块
        this.entryId;//入口文件ID,所有的ID都是相对于根目录的
        this.hooks.compile.call(compiler);

        this.buildModule(path.resolve(this.root,entry),true);//解析入口模块

        this.hooks.afterCompile.call(compiler);
        this.emitFile();
    }
    emitFile() {
        this.hooks.emit.call(this);
        let mainTemplate=fs.readFileSync(path.join(__dirname,'main2.ejs'),'utf8');
        let {modules,entryId}=this;
        let main=ejs.compile(mainTemplate)({modules,entryId});
        let {output: {path: dist,filename}}=this.options;
        fs.writeFileSync(path.join(dist,filename),main);
        Object.entries(this.chunks).forEach(([chunkIndex,chunk]) => {
            let chunkTemplate=fs.readFileSync(path.join(__dirname,'chunk.ejs'),'utf8');
            let chunkData=ejs.compile(chunkTemplate)({chunkIndex,chunk});
            let {output: {path: dist,filename}}=this.options;
            fs.writeFileSync(path.join(dist,`${chunkIndex}.bundle.js`),chunkData);
        });
        this.hooks.done.call(this);
    }

    buildModule(modulePath,isEntry,chunkIndex) {//解析模块和依赖的模块 路径是一个绝对路径
        let source=this.runLoaders(modulePath);      //获取源代码
        let moduleId='./'+path.relative(this.root,modulePath); //获取相对路径,因为所有的模块ID都是以项目根目录开始的
        if (isEntry) this.entryId=moduleId;
        let result=this.parse(source,path.dirname(moduleId));//获取AST解析结果
        let dependencies=result.dependencies;//获取次模块依赖的其它模块
        if (typeof chunkIndex != "undefined") {
            let currentChunk=typeof this.chunks[chunkIndex]=='undefined'? {}:this.chunks[chunkIndex];
            currentChunk[moduleId]=result.source;
            this.chunks[chunkIndex]=currentChunk;
        } else {
            this.modules[moduleId]=result.source;//记录一下模块ID和转换后的代码对应关系
        }
        dependencies.forEach(dependency=>this.buildModule(path.join(this.root,dependency),false,chunkIndex));
    }

    resolveModule(module) {
        return path.resolve(this.root,'node_modules',module)
    }

    runLoaders(modulePath) {
        let {module:{rules}}=this.options;
        let source=fs.readFileSync(modulePath,'utf8');
        for (let i=0;i<rules.length;i++){
            let rule=rules[i];
            if (rule.test.test(modulePath)) {
                let use=rule.use||rule.loader;
                if (Array.isArray(use)) {
                    let loaderIndex=use.length-1;
                    let  iterateLoaders = () => {
                        if (loaderIndex<0)return;
                        let currentLoader=require(this.resolveModule(use[loaderIndex--]));
                        source=currentLoader(source);
                        iterateLoaders();
                    }
                    iterateLoaders();
                } else {
                    let loader=require(this.resolveModule(typeof use=='string'? use:use.loader));
                    source=loader(source);
                }
                break;
            }
        }
        return source;
    }

    //参数为源代码和父路径
    parse(source,parentPath) {
        let compiler=this;
        const ast=babylon.parse(source,{
            plugins:['dynamicImport']
        })
        let dependencies=[];
        traverse(ast,{
            CallExpression(p) {
                if (p.node.callee.name=='require') {
                    let node=p.node;
                    node.callee.name='__webpack_require__';
                    let name=node.arguments[0].value;//取得参数里面的值
                    name += (name.lastIndexOf('.')>0? '':'.js');// 添加.js后缀
                    let moduleId='./'+path.join(parentPath,name);//取得此模块ID,也是相对于根路径的
                    dependencies.push(moduleId);
                    node.arguments=[t.stringLiteral(moduleId)];
                } else if (t.isImport(p.node.callee)) {
                    let node=p.node;
                    let name=node.arguments[0].value;//取得参数里面的值
                    name += (name.lastIndexOf('.')>0? '':'.js');// 添加.js后缀
                    let moduleId='./'+path.join(parentPath,name);//取得此模块ID,也是相对于根路径的
                    p.replaceWithSourceString(`
                    __webpack_require__.e(0)
                    .then(__webpack_require__.t.bind(null, "${moduleId}", 7))
                    `);
                    compiler.buildModule(path.join(compiler.root,moduleId),false,compiler.chunkIndex++);
              }
            }
        });
        source=generate(ast).code;
        return {source,dependencies};
    }
}

module.exports=Compiler;

3.8.2 main.ejs [#](#t193.8.2 main.ejs)

/******/ (function(modules) { // webpackBootstrap
    /******/     // install a JSONP callback for chunk loading
    /******/     function webpackJsonpCallback(data) {
    /******/         var chunkIds = data[0];
    /******/         var moreModules = data[1];
    /******/
    /******/
    /******/         // add "moreModules" to the modules object,
    /******/         // then flag all "chunkIds" as loaded and fire callback
    /******/         var moduleId, chunkId, i = 0, resolves = [];
    /******/         for(;i < chunkIds.length; i++) {
    /******/             chunkId = chunkIds[i];
    /******/             if(installedChunks[chunkId]) {
    /******/                 resolves.push(installedChunks[chunkId][0]);
    /******/             }
    /******/             installedChunks[chunkId] = 0;
    /******/         }
    /******/         for(moduleId in moreModules) {
    /******/             if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
    /******/                 modules[moduleId] = moreModules[moduleId];
    /******/             }
    /******/         }
    /******/         if(parentJsonpFunction) parentJsonpFunction(data);
    /******/
    /******/         while(resolves.length) {
    /******/             resolves.shift()();
    /******/         }
    /******/
    /******/     };
    /******/
    /******/
    /******/     // The module cache
    /******/     var installedModules = {};
    /******/
    /******/     // object to store loaded and loading chunks
    /******/     // undefined = chunk not loaded, null = chunk preloaded/prefetched
    /******/     // Promise = chunk loading, 0 = chunk loaded
    /******/     var installedChunks = {
    /******/         "main": 0
    /******/     };
    /******/
    /******/
    /******/
    /******/     // script path function
    /******/     function jsonpScriptSrc(chunkId) {
    /******/         return __webpack_require__.p + "" + chunkId + ".bundle.js"
    /******/     }
    /******/
    /******/     // The require function
    /******/     function __webpack_require__(moduleId) {
    /******/
    /******/         // Check if module is in cache
    /******/         if(installedModules[moduleId]) {
    /******/             return installedModules[moduleId].exports;
    /******/         }
    /******/         // Create a new module (and put it into the cache)
    /******/         var module = installedModules[moduleId] = {
    /******/             i: moduleId,
    /******/             l: false,
    /******/             exports: {}
    /******/         };
    /******/
    /******/         // Execute the module function
    /******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    /******/
    /******/         // Flag the module as loaded
    /******/         module.l = true;
    /******/
    /******/         // Return the exports of the module
    /******/         return module.exports;
    /******/     }
    /******/
    /******/     // This file contains only the entry chunk.
    /******/     // The chunk loading function for additional chunks
    /******/     __webpack_require__.e = function requireEnsure(chunkId) {
    /******/         var promises = [];
    /******/
    /******/
    /******/         // JSONP chunk loading for javascript
    /******/
    /******/         var installedChunkData = installedChunks[chunkId];
    /******/         if(installedChunkData !== 0) { // 0 means "already installed".
    /******/
    /******/             // a Promise means "currently loading".
    /******/             if(installedChunkData) {
    /******/                 promises.push(installedChunkData[2]);
    /******/             } else {
    /******/                 // setup Promise in chunk cache
    /******/                 var promise = new Promise(function(resolve, reject) {
    /******/                     installedChunkData = installedChunks[chunkId] = [resolve, reject];
    /******/                 });
    /******/                 promises.push(installedChunkData[2] = promise);
    /******/
    /******/                 // start chunk loading
    /******/                 var head = document.getElementsByTagName('head')[0];
    /******/                 var script = document.createElement('script');
    /******/                 var onScriptComplete;
    /******/
    /******/                 script.charset = 'utf-8';
    /******/                 script.timeout = 120;
    /******/                 if (__webpack_require__.nc) {
    /******/                     script.setAttribute("nonce", __webpack_require__.nc);
    /******/                 }
    /******/                 script.src = jsonpScriptSrc(chunkId);
    /******/
    /******/                 onScriptComplete = function (event) {
    /******/                     // avoid mem leaks in IE.
    /******/                     script.onerror = script.onload = null;
    /******/                     clearTimeout(timeout);
    /******/                     var chunk = installedChunks[chunkId];
    /******/                     if(chunk !== 0) {
    /******/                         if(chunk) {
    /******/                             var errorType = event && (event.type === 'load' ? 'missing' : event.type);
    /******/                             var realSrc = event && event.target && event.target.src;
    /******/                             var error = new Error('Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')');
    /******/                             error.type = errorType;
    /******/                             error.request = realSrc;
    /******/                             chunk[1](error);
    /******/                         }
    /******/                         installedChunks[chunkId] = undefined;
    /******/                     }
    /******/                 };
    /******/                 var timeout = setTimeout(function(){
    /******/                     onScriptComplete({ type: 'timeout', target: script });
    /******/                 }, 120000);
    /******/                 script.onerror = script.onload = onScriptComplete;
    /******/                 head.appendChild(script);
    /******/             }
    /******/         }
    /******/         return Promise.all(promises);
    /******/     };
    /******/
    /******/     // expose the modules object (__webpack_modules__)
    /******/     __webpack_require__.m = modules;
    /******/
    /******/     // expose the module cache
    /******/     __webpack_require__.c = installedModules;
    /******/
    /******/     // define getter function for harmony exports
    /******/     __webpack_require__.d = function(exports, name, getter) {
    /******/         if(!__webpack_require__.o(exports, name)) {
    /******/             Object.defineProperty(exports, name, { enumerable: true, get: getter });
    /******/         }
    /******/     };
    /******/
    /******/     // define __esModule on exports
    /******/     __webpack_require__.r = function(exports) {
    /******/         if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
    /******/             Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    /******/         }
    /******/         Object.defineProperty(exports, '__esModule', { value: true });
    /******/     };
    /******/
    /******/     // create a fake namespace object
    /******/     // mode & 1: value is a module id, require it
    /******/     // mode & 2: merge all properties of value into the ns
    /******/     // mode & 4: return value when already ns object
    /******/     // mode & 8|1: behave like require
    /******/     __webpack_require__.t = function(value, mode) {
    /******/         if(mode & 1) value = __webpack_require__(value);
    /******/         if(mode & 8) return value;
    /******/         if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    /******/         var ns = Object.create(null);
    /******/         __webpack_require__.r(ns);
    /******/         Object.defineProperty(ns, 'default', { enumerable: true, value: value });
    /******/         if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
    /******/         return ns;
    /******/     };
    /******/
    /******/     // getDefaultExport function for compatibility with non-harmony modules
    /******/     __webpack_require__.n = function(module) {
    /******/         var getter = module && module.__esModule ?
    /******/             function getDefault() { return module['default']; } :
    /******/             function getModuleExports() { return module; };
    /******/         __webpack_require__.d(getter, 'a', getter);
    /******/         return getter;
    /******/     };
    /******/
    /******/     // Object.prototype.hasOwnProperty.call
    /******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    /******/
    /******/     // __webpack_public_path__
    /******/     __webpack_require__.p = "";
    /******/
    /******/     // on error function for async loading
    /******/     __webpack_require__.oe = function(err) { console.error(err); throw err; };
    /******/
    /******/     var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
    /******/     var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
    /******/     jsonpArray.push = webpackJsonpCallback;
    /******/     jsonpArray = jsonpArray.slice();
    /******/     for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
    /******/     var parentJsonpFunction = oldJsonpFunction;
    /******/
    /******/
    /******/     // Load entry module and return exports
    /******/     return __webpack_require__(__webpack_require__.s = "<%-entryId%>");
    /******/ })
    /************************************************************************/
    /******/ ({
        <%
        for(let id in modules){
            let source = modules[id];%>
        /***/ "<%-id%>":
        /***/ function(module, exports,__webpack_require__) {

        eval(`<%-source%>`);

        /***/ },
        <%}%>
    /******/ });

3.8.3 chunke.ejs [#](#t203.8.3 chunke.ejs)

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[<%=chunkIndex%>],{
    <%
        for(let id in chunk){
            let source = chunk[id];%>
        /***/ "<%-id%>":
        /***/ function(module, exports,__webpack_require__) {

        eval(`<%-source%>`);

        /***/ },
        <%}%>

    }]);

3.8.4 测试代码 [#](#t213.8.4 测试代码)

index.js

let loadButton=document.querySelector('#loadButton');
let base=require('./base');
loadButton.addEventListener('click',() => {
    import('./video').then(video => {
        console.log(video.default+base);
    });
});

video.js

module.exports='video';

base.js

module.exports='base';

参考资料 #

Gitalking ...

Markdown is supported

Be the first guy leaving a comment!