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 ...
Be the first guy leaving a comment!