本文源码 在此 。
起步 检查 node.js 和 npm 的版本。
1 2 3 4 $ node -v v16.13.2 $ npm -v 8.1.2
新建一个目录,进入。新建 package.json
文件。
1 2 3 $ mkdir webpack-demo$ cd webpack-demo$ npm init -y
为了提高下载速度,安装 cnpm。
1 $ sudo npm i -g cnpm --registry=https://registry.npmmirror.com
用 cnpm 安装 webpack 及其命令行工具。检查安装的版本。
1 2 3 4 5 $ cnpm i -D webpack webpack-cli $ npx webpack -v webpack: 5.67.0 webpack-cli: 4.9.2 webpack-dev-server not installed
在 package.json
的 scripts
中添加 "build": "webpack"
。
1 2 3 "scripts" : { "build" : "webpack" }
这样就可以用 npm run build
命令来执行一次打包。
新建两个子目录 src
和 dist
,分别用来放置源文件和打包输出。
新建 ./src/app.js
文件,作为打包入口。
新建 index.html
文件,假设打包输出为 ./dist/bundle.js
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="utf-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1, shrink-to-fit=no" > <title > Hello World!</title > </head > <body > <p > Hello World!</p > <script src ="./dist/bundle.js" > </script > </body > </html >
最终的目录结构:
1 2 3 4 5 6 7 8 9 $ tree -L 2 -I "node_modules" . |-- dist |-- index.html |-- package.json `-- src `-- app.js 2 directories, 3 files
基本配置 习惯上将 webpack 的配置文件命名为 webpack.config.js
,须手动创建,放在项目根目录下,webpack 会自动引用此配置文件。
1 $ touch webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const path = require ('path' )module .exports = { mode : 'production' , entry : './src/app.js' , output : { filename : 'bundle.js' , path : path.resolve (__dirname, 'dist' ), publicPath : '/' }, module : {}, plugins : [] }
尝试进行一次打包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ npm run build > webpack-demo@1.0.0 build > npx webpack asset bundle.js 24 bytes [compared for emit] [minimized] (name: main) ./src/app.js 23 bytes [built] [code generated] webpack 5.67.0 compiled successfully in 254 ms $ tree -L 2 -I "node_modules" . |-- dist | `-- bundle.js |-- index.html |-- package.json |-- src | `-- app.js `-- webpack.config.js 2 directories, 5 files
尝试用浏览器打开 index.html
,看是否有弹窗。
认识装载器 装载器在 webpack.config.js
的 module.rules
中列出。
1 2 3 4 module : { rules : [ ] }
rules
中的元素是对象类型,通常包含 test
use
两个属性。test
匹配文件名,use
列出装载器,由此形成一条流水线(调用顺序与书写顺序相反)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 module : { rules : [ { test : /\.less$/ , use : [ 'style-loader' , { loader : 'css-loader' , options : { importLoaders : 1 } }, { loader : 'less-loader' , options : { noIeCompat : true } } ] } ] }
上例表示以 .less
结尾的文件依次用 less-loader
css-loader
style-loader
处理。
只需一个装载器时,用 loader
代替 use
。
1 2 3 4 { test : /\.(png|svg|jpg|gif)$/ , loader : 'file-loader' }
添加装载器 安装上述提到的 3 个的装载器:
1 $ cnpm i -D style-loader css-loader file-loader
css-loader
负责解析 .js
文件中的 import '.css'
以及 .css
文件中的 @import '.css'
。
style-loader
负责生成 <style>
标签并追加到 <head>
标签中。
在 webpack.config.js
的 module.rules
中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module : { rules : [ { test : /\.css$/ , use : ['style-loader' , 'css-loader' ] }, { test : /\.(png|svg|jpg|gif)$/ , loader : 'file-loader' }, { test : /\.(woff|woff2|eot|ttf|otf)$/ , loader : 'file-loader' } ] }
新建 ./src/app.css
文件。
1 2 3 p { background-color : blue; }
在 ./src/app.js
中引入:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ rm -f ./dist/* && npm run build$ tree -L 2 -I "node_modules" . |-- dist | `-- bundle.js |-- index.html |-- package.json |-- src | |-- app.css | `-- app.js `-- webpack.config.js 2 directories, 6 files
检查 <p>
标签的背景色。
使用 Bootstrap 5.x 安装 Bootstrap 及其依赖包。
1 $ cnpm i -D bootstrap @popperjs/core
导入 Bootstrap 的 JavaScript 和 CSS,在 ./src/app.js
的顶部插入:
1 2 import 'bootstrap' import 'bootstrap/dist/css/bootstrap.min.css'
在 index.html
中使用 Bootstrap 的样式类 text-success
。
1 <p class ="text-danger" > Hello World!</p >
重新打包,检查字体的颜色。
省略后缀名 在 .js
文件中用 import
导入模块时,可以省略模块的后缀名,但必须在 webpack.config.js
的 resolve.extensions
中列出。
1 2 3 resolve : { extensions : ['.js' , '.json' , '.css' , '.sass' , '.vue' ] }
多入口 新建 JS 文件。
webpack.config.js
中,entry
改成对象类型,output.filename
用 [name]
拼接。
1 2 3 4 5 6 7 entry : { app : './src/app.js' , admin : './src/admin.js' }, output : { filename : '[name].bundle.js' , },
相应修改 index.html
:
1 2 <script src ="./dist/app.bundle.js" > </script > <script src ="./dist/admin.bundle.js" > </script >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ rm -f ./dist/* && npm run build$ tree -L 2 -I "node_modules" . |-- dist | |-- admin.bundle.js | |-- app.bundle.js | |-- app.bundle.js.LICENSE.txt |-- index.html |-- package.json |-- src | |-- admin.js | |-- app.css | `-- app.js `-- webpack.config.js 2 directories, 9 files
重新打包,检查是否有两次弹窗。
分离第三方库 可以单独打包第三方库,而不在 .js
文件中引入,只须在 entry.vendors
中列出第三方库,这会得到 vendors.bundle.js
文件(文件名取决于 output.filename
)。
1 2 3 entry : { vendors : ['bootstrap' , '@popperjs/core' ] }
在 index.html
中添加:
1 <script src ="./dist/vendors.bundle.js" > </script >
注释 ./src/app.js
中的 import 'bootstrap'
。
剥离 CSS 剥离 .js
引入的 .css
,合并成单独的 .css
文件,每个入口对应一个。
安装插件 mini-css-extract-plugin
。
1 $ cnpm i -D mini-css-extract-plugin
在 plugins
中实例化插件,在 module.rules
中应用插件。同时,为方便演示:
删除 ./src/admin.js
,相应修改 entry
。
修改 output.filename
。
用 MiniCssExtractPlugin.loader
替换 style-loader
。
在 plugins
中初始化 MiniCssExtractPlugin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const MiniCssExtractPlugin = require ('mini-css-extract-plugin' ) entry : { }, output : { filename : '[name].js' , }, module : { rules : [ { test : /\.css/ , use : [MiniCssExtractPlugin .loader , 'css-loader' ] }, ] }, plugins : [ new MiniCssExtractPlugin ({ filename : '[name].css' }) ]
修改 index.html
:
1 2 3 4 <link rel ="stylesheet" href ="./dist/app.css" > <script src ="./dist/vendors.js" > </script > <script src ="./dist/app.js" > </script >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ rm -f ./dist/* && npm run build$ tree -L 2 -I "node_modules" . |-- dist | |-- app.css | |-- app.js | |-- vendors.js | `-- vendors.js.LICENSE.txt |-- index.html |-- package.json |-- src | |-- app.css | `-- app.js `-- webpack.config.js 2 directories, 9 files
压缩 CSS 安装插件 css-minimizer-webpack-plugin
。
1 $ cnpm i -D css-minimizer-webpack-plugin
在 optimization.minimizer
中实例化即可。
1 2 3 4 5 const CssMinimizerPlugin = require ('css-minimizer-webpack-plugin' ) optimization : { minimizer : ['...' , new CssMinimizerPlugin ()] }
...
表示对 minimizer
进行扩展而不是覆盖,以保留内置的 .js
压缩插件。
自动清理打包输出 安装插件 clean-webpack-plugin
。
1 $ cnpm i -D clean-webpack-plugin
在 plugins
中实例化即可。
1 2 3 4 5 const { CleanWebpackPlugin } = require ('clean-webpack-plugin' ) plugins : [ new CleanWebpackPlugin () ]
带 hash 的文件名、自动生成 index.html 安装插件 html-webpack-plugin
。
1 $ cnpm i -D html-webpack-plugin
文件名用 [fullhash]
拼接。在 plugins
中调用 HtmlWebpackPlugin
指定模板 .ejs
、输出文件名、是否将 .css
.js
直接嵌入模板而不通过 <link>
<script>
引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const HtmlWebpackPlugin = require ('html-webpack-plugin' ) output : { filename : '[name].[fullhash].js' , publicPath : '/' }, plugins : [ new MiniCssExtractPlugin ({ filename : '[name].[fullhash].css' }), new CleanWebpackPlugin (), new HtmlWebpackPlugin ({ template : './src/index.ejs' , filename : 'index.html' , inject : false }) ]
删除没用的 index.html
,新建模板 ./src/index.ejs
。
1 2 $ rm -f ./index.html$ touch ./src/index.ejs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Hello World!</title> <link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[0] %>"> </head> <body> <p class="text-danger">Hello World!</p> <script src="<%= htmlWebpackPlugin.files.js[0] %>"></script> <script src="<%= htmlWebpackPlugin.files.js[1] %>"></script> </body> </html>
重新打包,检查是否正确生成 ./dist/index.html
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ npm run build $ tree -L 2 -I "node_modules" . |-- dist | |-- app.7faf852820591e38bbd0.css | |-- app.7faf852820591e38bbd0.js | |-- index.html | |-- vendors.7faf852820591e38bbd0.js | `-- vendors.7faf852820591e38bbd0.js.LICENSE.txt |-- package.json |-- src | |-- app.css | |-- app.js | `-- index.ejs `-- webpack.config.js 2 directories, 10 files
开发时配置 安装 webpack-merge
。
1 $ cnpm i -D webpack-merge
新增配置文件 webpack.dev.config.js
。
1 $ touch webpack.dev.config.js
1 2 3 4 5 6 7 8 9 const { merge } = require ('webpack-merge' )const common = require ('./webpack.config.js' )module .exports = merge (common, { mode : 'development' , devtool : 'inline-source-map' })
用处见下文。
使用 webpack-dev-server webpack-dev-server
可以快速开启一个 Web 服务,并在文件发生改变时重新编译并通知浏览器。
安装 webpack-dev-server
。
1 $ cnpm i -D webpack-dev-server
在 webpack.dev.config.js
中新增配置项 devServer
。
1 2 3 4 5 6 devtool : 'inline-source-map' ,devServer : { host : "127.0.0.1" , port : 8080 , historyApiFallback : true }
修改 package.json
的 scripts
。
1 2 3 "scripts" : { "dev" : "webpack serve -c webpack.dev.config.js --open" }
webpack 的 serve
命令用于启动 webpack-dev-server,--open
选项用于启动浏览器。
执行 npm run dev
查看效果。
1 2 3 4 5 6 7 8 9 10 11 12 $ tree -L 2 -I "node_modules" . |-- dist |-- package.json |-- src | |-- app.css | |-- app.js | `-- index.ejs |-- webpack.config.js `-- webpack.dev.config.js 2 directories, 6 files
使用 Vue.js 3.x 安装。
1 $ cnpm i -D vue@next @vue/compiler-sfc vue-loader@next
修改 webpack.config.js
的 module.rules
和 plugins
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const webpack = require ('webpack' )const { VueLoaderPlugin } = require ("vue-loader" ) module : { rules : [ { test : /\.vue$/ , loader : 'vue-loader' }, ] }, plugins : [ new VueLoaderPlugin () ],
修改 ./src/index.ejs
。
1 2 3 4 5 <body> <div id="app" v-cloak></div> <script src="<%= htmlWebpackPlugin.files.js[0] %>"></script> </body>
修改 ./src/app.css
。
1 2 3 [v-cloak] { display : none; }
新增文件 ./src/app.vue
。
1 2 3 4 5 6 7 8 9 10 11 12 13 <template> <p @click="onClick" class="text-danger">Hello World!</p> </template> <script> export default { methods: { onClick() { alert('clicked') } } } </script>
在 ./src/app.js
中添加:
1 2 3 4 import { createApp } from 'vue' import app from './app.vue' createApp (app).mount ('#app' )
1 2 3 4 5 6 7 8 9 10 11 12 13 $ tree -L 2 -I "node_modules" . |-- dist |-- package.json |-- src | |-- app.css | |-- app.js | |-- app.vue | `-- index.ejs |-- webpack.config.js `-- webpack.dev.config.js 2 directories, 7 files
执行 npm run dev
查看效果。
使用 Electron 16.x 在 webpack.config.js
中增加 target
并修改 output
。
1 2 3 4 5 6 7 8 9 10 11 target : 'electron-renderer' ,output : { filename : '[name].js' , publicPath : './' plugins : [ new MiniCssExtractPlugin ({ filename : '[name].css' }),
必须设定 target
,否则不能在渲染进程中使用 fs
path
等模块。
安装 Electron。
1 2 3 4 5 6 7 $ cnpm i -D electron electron-packager $ npx electron -v v16.0.7 $ npx electron-packager --version Electron Packager 15.2.0 Node v15.10.0 Host Operating system: win32 10.0.19042 (x64)
新建 main.js
作为主进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const { app, BrowserWindow } = require ('electron' )function createWindow ( ) { const options = { width : 400 , height : 300 , webPreferences : { nodeIntegration : true } } const win = new BrowserWindow (options) win.loadFile ('./dist/index.html' ) } app.whenReady ().then (() => { createWindow () app.on ('activate' , () => { if (BrowserWindow .getAllWindows ().length === 0 ) createWindow () }) }) app.on ('window-all-closed' , () => { if (process.platform !== 'darwin' ) app.quit () })
win.loadFile('./dist/index.html');
HTML 文档的路径相对于 Electron 的工作目录。HTML 文档中引用的外部文件(如 CSS、JS 文件等)的路径则相对于 HTML 文档本身。
修改 package.json
,添加 main
字段。
1 2 3 4 5 6 7 "main" : "main.js" ,"scripts" : { "build" : "webpack" , "dev" : "electron ." , "test" : "webpack && electron ." , "make" : "electron-packager . --ignore='\\.gitignore|webpack*\\.js|node_modules|src' --overwrite --download.mirrorOptions.mirror=https://npm.taobao.org/mirrors/electron/" }
--ignore
忽略 .gitignore
webpack*.js
node_modules/
src/
等文件。
--overwrite
如存在旧的软件包,直接覆盖。
--download
从淘宝 NPM 镜像下载。
在 ./src/index.ejs
添加:
1 <meta http-equiv ="Content-Security-Policy" content ="default-src 'self'; script-src 'self'" >
用 webpack 打包,用 Electron 运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 $ npm run build $ tree -L 2 -I "node_modules" . |-- dist | |-- app.css | |-- app.js | |-- index.html | |-- vendors.js | `-- vendors.js.LICENSE.txt |-- main.js |-- package.json |-- src | |-- app.css | |-- app.js | |-- app.vue | `-- index.ejs |-- webpack.config.js `-- webpack.dev.config.js 2 directories, 13 files $ npm run dev
可以用 npm test
代替以上两个命令。
打包成 .exe
文件。
1 2 3 4 5 6 7 $ npm run make > webpack-demo@1.0.0 make > electron-packager . --ignore='\\.gitignore|webpack*\\.js|node_modules|src' --overwrite --download.mirrorOptions.mirror=https://npm.taobao.org/mirrors/electron/ Packaging app for platform win32 x64 using electron v11.3.0 Wrote new app to...
使用 Element Plus 安装下列两个插件就可以直接在 .vue
中使用 Element Plus 组件,而不需要任何 import
语句。
1 $ npm i -D element-plus unplugin-vue-components unplugin-auto-import
修改 webpack.config.js
的 module.rules
和 plugins
两个字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const AutoImport = require ('unplugin-auto-import/webpack' )const Components = require ('unplugin-vue-components/webpack' )const { ElementPlusResolver } = require ('unplugin-vue-components/resolvers' ) module : { rules : [ { test : /\.m?js$/ , resolve : { byDependency : { esm : { fullySpecified : false } } } } ] }, plugins : [ AutoImport ({ resolvers : [ElementPlusResolver ()] }), Components ({ resolvers : [ElementPlusResolver ()] }) ]
在 .vue
中使用 Element Plus 提供的按钮组件。
1 2 3 <template> <el-button>I am ElButton</el-button> </template>