首先,新建一個空文件夾,編輯器(webstrom)打開文件夾,執行npm init -y,生成package.json,在根目錄新建webpack.config.js,加入如下代碼(webpack 4.0的基礎配置)
const path=require('path');
module.exports={
entry:'./src/index.js',
mode:'development',
output:{
path:path.resolve(__dirname,'./dist'),
filename:'main.js'
}
};
新建src目錄,添加index.js,exop.js
expo.js
export const add=(a,b)=>{
return a+b
}
export const minus=function (a,b) {
return a-b
}
index.js
import {add,minus} from "./expo.js"
add(1,2)
console.log("hello webpack")
執行命令 npx webpack,看到生成的文件/dist/main.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, __webpack_require__);
// Flag the module as loaded
module.l = true;
// Return the exports of the module
return module.exports;
}
...
// Object.prototype.hasOwnProperty.call
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// __webpack_public_path__
__webpack_require__.p = "";
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
...
打包後生成的代碼,可以直接在瀏覽器的控制檯運行,大致的意思就是,webpack實現了一個webpack_require來實現自己的模塊化,把代碼都緩存在installedModules裏,代碼文件以對象傳遞進來,key是路徑,value是包裹的代碼字符串,並且代碼內部的require,都被替換成了webpack_require處理依賴模塊的路徑
如何自己實現一個簡單的webpack打包流程呢?
實現步驟
- 基礎配置,webpack會讀取配置
- 找到入口模塊
- 入口分析
- 分析以來模塊(拿到模塊的路徑)
- 分析內容(並對內容處理)
- 編譯內容
- 依賴模塊(遞歸找到依賴)
- 分析以來模塊
- 分析依賴模塊(並對內容處理)
- 編譯內容
- 生成bundle.js,代碼可以直接在瀏覽器中運行
自己實現一個bundle.js
- 模塊分析:讀取入口文件,分析代碼
新建文件./lib/webpack.js,其中利用了node的fs,讀取文件內容,爲了拿到文件中依賴,不推薦使用字符串截取,引入的模塊名越多,就越麻煩,不靈活,推薦使用@babel/parser,這是babel7的工具,分析包括es6的內部的語法,返回一個ast抽象樹
npm i @babel/parser --save
const fs = require('fs')//node的核心模塊fs
constructor(options) {
console.log(options)
const {entry, output} = options
this.entry = entry
this.output = output
//存所有模塊信息
this.modules = []
}
run() {//入口函數
const info = this.parse(this.entry)
console.log(info)
}
parse(entryFile) {
//! 分析入口模塊的內容
const content = fs.readFileSync(entryFile, 'utf-8')
console.log(content)
//!分析出哪些是依賴?以及依賴的路徑
const ast = parser.parse(content, {
sourceType: 'module'
})
console.log(ast.program.body)
}
新建build.js
//! 拿到webpack的配置文件
const options =require("./webpack.config.js")
const webpack=require('./lib/webpack')
//類實例化
new webpack(options).run()
執行node build.js,打印ast body部分的內容
[ Node {
type: 'ImportDeclaration',
start: 0,
end: 35,
loc: SourceLocation { start: [Position], end: [Position] },
specifiers: [ [Node], [Node] ],
source:
Node {
type: 'StringLiteral',
start: 24,
end: 35,
loc: [SourceLocation],
extra: [Object],
value: './expo.js' },
trailingComments: [ [Object] ] },
Node {
type: 'ExpressionStatement',
start: 44,
end: 52,
loc: SourceLocation { start: [Position], end: [Position] },
expression:
Node {
type: 'CallExpression',
start: 44,
end: 52,
loc: [SourceLocation],
callee: [Node],
arguments: [Array] } },
Node {
type: 'ExpressionStatement',
start: 54,
end: 82,
loc: SourceLocation { start: [Position], end: [Position] },
expression:
Node {
type: 'CallExpression',
start: 54,
end: 82,
loc: [SourceLocation],
callee: [Node],
arguments: [Array] },
trailingComments: [ [Object] ] } ]
可以看到,index.js中的三行代碼分別被解析成導入、表達式、表達式
import {add,minus} from "./expo.js" //解析導入
add(1,2)////解析成表達式
console.log("hello webpack")//解析成表達式