前提
- 已安裝node(版本號(hào)>4.0,已自帶NPM)
- mac機(jī)器
- 有一個(gè)空目錄
要實(shí)現(xiàn)的功能
- JSX語法,ES6語法,LESS語法編寫的模塊轉(zhuǎn)化為瀏覽器可執(zhí)行的模塊
- 代碼的混淆壓縮
- 多頁面多入口
- 提取公共文件
無webpack.config.js配置打包
快速構(gòu)建
package.json文件。
npm init -y安裝webpack4及其命令行接口
npm i webpack webpack-cli --save-devpackage.json文件增加build參數(shù)
"scripts": {
"build": "webpack"
}
- 創(chuàng)建
./src/index.js文件
增加內(nèi)容
console.log(`這是入口文件`);
- 終端執(zhí)行
npm run build
目錄下多了一個(gè)./dist/main.js。
這個(gè)文件是webpack對(duì)./src/index.js的打包結(jié)果。
production和development模式
- 修改
package.json文件的scripts字段
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
- 分別執(zhí)行
npm run dev或npm run build
你會(huì)看到./dist/main.js不同的變化。
production模式下,默認(rèn)對(duì)打包的進(jìn)行minification(文件壓縮),Tree Shaking(只導(dǎo)入有用代碼),scope hoisting(作用域提升)等等操作。
總之是讓打包文件更小。
development模式下,對(duì)打包文件不壓縮,同時(shí)打包速度更快。
如果沒指定任何模式,默認(rèn)是production模式。
ES6和React
安裝對(duì)應(yīng)依賴包
npm i babel-core babel-loader babel-preset-env react react-dom babel-preset-react --save-dev新建
.babelrc文件,進(jìn)行相關(guān)配置
{
"presets": ["env", "react"]
}
- 新建
webpack.config.js文件,進(jìn)行相關(guān)配置
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
- 新增
./src/app.js以及修改./src/index.js
./src/app.js內(nèi)容如下:
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
return (
<div>
<p>React here!</p>
</div>
);
};
export default App;
ReactDOM.render(<App />, document.getElementById("app"));
./src/index.js內(nèi)容如下:
import App from "./App";
- 終端執(zhí)行
npm run build
使用html-webpack-plugin插件對(duì)html進(jìn)行打包
新建./src/index.html文件,內(nèi)容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>webpack4入門</title>
</head>
<body>
<div id="app">
</div>
</body>
</html>
安裝依賴包。
npm i html-webpack-plugin html-loader --save-dev
修改webpack.config.js配置。
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
})
]
};
終端執(zhí)行npm run build命令。
你會(huì)看到項(xiàng)目多了個(gè)./dist/index.html文件。
使用webpack-dev-server插件
安裝依賴包。
npm i webpack-dev-server --save-dev
修改package.json文件。
"scripts": {
"start": "webpack-dev-server --mode development --open",
"build": "webpack --mode production"
}
修改webpack.config.js文件,新增devServer配置。
devServer: {
contentBase: require('path').join(__dirname, "dist"),
compress: true,
port: 8033,
host: "127.0.0.1",
}
終端執(zhí)行npm run start便可以啟動(dòng)webpack dev server。
使用Hot Module Replacement
Hot Module Replacement有針對(duì)React,Vue,Redux,Angular,樣式等等。
這里我們以React Hot Loader為例。
安裝依賴包。
npm i react-hot-loader --save-dev
修改.babelrc文件,新增plugins選項(xiàng)。
{
"plugins": ["react-hot-loader/babel"]
}
修改webpack.config.js文件。
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const webpack = require('webpack'); // 新增
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
}
]
},
devtool: 'inline-source-map',
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new webpack.NamedModulesPlugin(), // 新增
new webpack.HotModuleReplacementPlugin() //新增
],
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 8033,
host: "127.0.0.1",
hot: true // 新增
}
};
修改./src/app.js文件內(nèi)容如下:
import React from "react";
import ReactDOM from "react-dom";
import { hot } from 'react-hot-loader' // 新增
const App = () => {
return (
<div>
<p>這是一個(gè)測試文件!真得是動(dòng)態(tài)更新啊</p>
<div>好棒棒啊</div>
</div>
);
};
export default hot(module)(App); // 修改
ReactDOM.render(<App />, document.getElementById("app"));
終端執(zhí)行npm run start便可以啟動(dòng)webpack dev server。
然后修改./src/app.js看下效果。
動(dòng)態(tài)加模塊
- 動(dòng)態(tài)加載普通JS模塊
修改.babelrc文件添加"syntax-dynamic-import"插件
{
"presets": [
"env",
"react"
],
"plugins": ["react-hot-loader/babel","syntax-dynamic-import"]
}
然后在業(yè)務(wù)代碼文件使用import語法即可
import('模塊路徑').then(mod => {
someOperate(mod); //mod是module的簡寫,表示加載成功后的異步組件
});
如果沒有使用syntax-dynamic-import插件會(huì)導(dǎo)致構(gòu)建失敗,并提示:
Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level
- 動(dòng)態(tài)加載React模塊
如同動(dòng)態(tài)加載普通JS模塊,修改.babelrc文件添加"syntax-dynamic-import"插件。
然后安裝react-loadable這個(gè)NPM包
npm install react-loadable --save
接著如下方式引入React組件模塊即可。
import Loadable from 'react-loadable';
const LoadableBar = Loadable({
loader: () => import('react組件模塊路徑'),
loading() {
return <div>Loading...</div>
}
});
class MyComponent extends React.Component {
render() {
return <LoadableBar/>;
}
}
多頁面多入口打包
修改webpack.config.js如下
...
entry: {
// 把html 加入 entry。目的是修改html文件也能hot reload。
// 不要在生產(chǎn)環(huán)境這么做。因?yàn)檫@會(huì)導(dǎo)致 chunk 文件包含了無用的 html 片段。
page0: ['./src/pages/page0/index.js','./src/template/page0.html'],
page1: './src/pages/page1/index.js',
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/template/page0.html",
filename: "./page0.html",
chunksSortMode: 'none',
chunks: ["page0"],
}),
new HtmlWebPackPlugin({
template: "./src/template/page1.html",
filename: "./page1.html",
chunksSortMode: 'none',
chunks: ["page1"],
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
...
對(duì)應(yīng)文件存放目錄結(jié)構(gòu)修改如圖

第三方庫和業(yè)務(wù)代碼分開打包
基本策略是:
- 提取樣式文件
- 分離公共文件(運(yùn)行時(shí),node_modules,業(yè)務(wù)的共同依賴)
- 懶加載大文件
react-loadable
簡單分離公共文件和業(yè)務(wù)文件
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'common',
priority: 10,
chunks: 'initial'
}
}
}
}
分離業(yè)務(wù)文件,node_modules,業(yè)務(wù)的共同依賴,webpack運(yùn)行時(shí)
runtimeChunk: {
name: 'manifest'
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
},
commons: {
chunks: "all",
name: 'commons',
/**
* minSize 默認(rèn)為 30000
* 想要使代碼拆分真的按照我們的設(shè)置來
* 需要減小 minSize
*/
minSize: 0,
// 至少為兩個(gè) chunks 的公用代碼
minChunks: 2
}
}
}
}
這里打包出來的文件有vendros.js(node_modules),commons.js(業(yè)務(wù)的共同依賴),manifest.js(webpack運(yùn)行時(shí)),業(yè)務(wù)文件
手動(dòng)指定業(yè)務(wù)的共同依賴
entry: {
// html可實(shí)時(shí)刷新修改
page0: ['./src/pages/page0/index.js', './src/template/page0.html'],
page1: './src/pages/page1/index.js',
page2: './src/pages/page2/index.js',
pageCommon: ['./src/common/page0-1.js', './src/common/page0-2.js'],
},
optimization: {
runtimeChunk: {
name: 'manifest'
},
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
},
}
}
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/template/page0.html",
filename: "./page0.html",
chunksSortMode: 'none',
chunks: ["page0", "pageCommon", "vendors","manifest"],
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
手動(dòng)指定共同依賴后,就不要再讓webpack自動(dòng)分析共同依賴,否則手動(dòng)的共同依賴打包出來不生效。
參考
https://www.valentinog.com/blog/webpack-4-tutorial/
https://github.com/fenivana/webpack-and-spa-guide
https://segmentfault.com/a/1190000014685887