webpack构建原理(实现一个简易的webpack构建器)


webpack构建原理(实现一个简易的webpack构建器)

    • webpack的构建原理:
    • 实现代码:
    • 执行```node bundle.js```的结果
【webpack构建原理(实现一个简易的webpack构建器)】
webpack的构建原理:
  • webpack的构建原理所在的核心文件:./lib/webpack-structure.js
  • webpack配置文件:./webpack.config.js
  • webpack的执行文件:./bundle.js
  • 源码所在的文件:./src/index.js
  • 源码依赖的文件:./src/expo.js
实现代码:
  • 工程结构:
    webpack构建原理(实现一个简易的webpack构建器)
    文章图片
  • webpack-structure.js
const fs = require("fs") const parser = require("@babel/parser") const traverse = require("@babel/traverse").default const path = require("path") const {transformFromAst} = require("@babel/core")module.exports = class Webpack { constructor(options) { const {entry, output} = options; this.entry = entry; this.output = output; // 构建结果存储 this.modules = [] }run() { // 1、处理入口文件 const info = this.parse(this.entry) this.modules.push(info); ///2、处理入口文件的相关依赖 for (let i = 0; i < this.modules.length; i++) { const item = this.modules[i] const {dependencies} = item if (dependencies) { for (let key in dependencies) { this.modules.push(this.parse(dependencies[key])) } } }///3、结果数组结构转换为对象 const obj = {} this.modules.forEach(item => { obj[item.entryFile] = { dependencies: item.dependencies, code: item.code } })// console.log("webpack构建后的文件输出:\n", obj); ///4、生成浏览器可执行的代码字符串 this.generateFile(obj)} /** * 解析入口文件以及相关依赖模块 * @param entryFile * @return {{code: *, entryFile: *, dependencies: {}}} */ parse(entryFile) {// 拿到入口文件的内容 const content = fs.readFileSync(entryFile, "utf-8")// 把内容抽象成语法树,分析哪些是依赖 const ast = parser.parse(content, { sourceType: "module" })// 提取依赖模块的路径 const dependencies = {} traverse(ast, { ImportDeclaration({node}) { const newPathName = `${path.dirname(entryFile)}/${node.source.value.split("/")[1]}`; dependencies[node.source.value] = newPathName } })// 分析编译内容 const {code} = transformFromAst(ast, null, { presets: ["@babel/preset-env"] })// 返回处理后的相关信息 return { entryFile, dependencies, code } } /** * 文件编译输出 * @param code */ generateFile(code) {// 生成bundle.js=> ./dist/bundle.js const filePath = path.join(this.output.path, this.output.filename)const newCode = JSON.stringify(code) const bundle = `(function(graph){function require(module){function localRequire(relativePath){ return require(graph[module].dependencies[relativePath]) }var exports={}; (function(require,exports,code){eval(code)})(localRequire,exports,graph[module].code)return exports; }require('${this.entry}')})(${newCode})`this.hasDir(this.output.path).then(msg => {fs.writeFileSync(filePath, bundle, "utf-8")}).catch(error => {console.log(error); return this.createDir(this.output.path)}).then(msg => {console.log(msg) fs.writeFileSync(filePath, bundle, "utf-8") console.log(`webpack编译文件成功,内容输出到文件${filePath}`)}).catch(error => {console.log(error); }) } } /** * 判断输出目录是否存在,不存在则创建 * @param path * @return {Promise} */ hasDir(path) { return new Promise((resolve, reject) => { fs.stat(path, (err, msg) => { if (err) { reject(`目录${path}不存在,系统开始自动创建目录...`) } else { resolve() } }) }) }/** * 创建目录 * @param path * @return {Promise} */ createDir(path) { return new Promise((resolve, reject) => { let err = fs.mkdirSync(path, {}) if (err) { reject(`创建目录${path}失败...`) } else { resolve(`系统创建目录${path}成功,webpack开始编译文件...`) } }) }

  • webpack.config.js
const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' } };

  • bundle.js
// 获取webpack的配置文件 const options = require("./webpack.config.js")// 引入webpack构建原理的核心文件 const Webpack = require("./lib/webpack-structure.js")new Webpack(options).run()

  • index.js
import {add} from "./expo.js"add(1, 2)console.log("hello webpack");

  • expo.js
export const add = function (a, b) { return a + b }

执行node bundle.js的结果
  • 在dist目录下生成main.js文件
(function(graph){function require(module){function localRequire(relativePath){ return require(graph[module].dependencies[relativePath]) }var exports={}; (function(require,exports,code){eval(code)})(localRequire,exports,graph[module].code)return exports; }require('./src/index.js')})({"./src/index.js":{"dependencies":{"./expo.js":"./src/expo.js"},"code":"\"use strict\"; \n\nvar _expo = require(\"./expo.js\"); \n\n(0, _expo.add)(1, 2); \nconsole.log(\"hello webpack\"); "},"./src/expo.js":{"dependencies":{},"code":"\"use strict\"; \n\nObject.defineProperty(exports, \"__esModule\", {\nvalue: true\n}); \nexports.mini = exports.add = void 0; \n\nvar add = function add(a, b) {\nreturn a + b; \n}; \n\nexports.add = add; \n\nvar mini = function mini(a, b) {\nreturn a - b; \n}; \n\nexports.mini = mini; "}})

  • 将main.js文件中的代码拷贝到浏览器的控制台执行,成功输出“hello webpack”
    webpack构建原理(实现一个简易的webpack构建器)
    文章图片

    推荐阅读