關(guān)于 webpack 相關(guān)的文章太多了闸拿,何不一起從零開始手寫一個(gè)配置呢斩芭?
真的3秒能打包一個(gè)three.js項(xiàng)目嗎捌浩?真的滩愁,后面會(huì)提供源文件地址哦俐筋。
要打包的項(xiàng)目是這個(gè)樣子的抡秆。
從零開始
關(guān)于 three.js
的安裝和使用部分都省略大溜。
首先是最基礎(chǔ)的差油。我們需要安裝
-
cross-env
目前最流行的運(yùn)行跨平臺(tái)設(shè)置和使用環(huán)境變量的腳本 -
webpack
+webpack-cli
+webpack-dev-server
:三'賤'客,項(xiàng)目必備
參考常規(guī)webpack配置結(jié)構(gòu)需要3個(gè)最基礎(chǔ)文件:
- webpack 基礎(chǔ)配置文件憾筏,暫命名為
webpack.base.js
- webpack 開發(fā)配置文件嚎杨,暫命名為
webpack.dev.js
- webpack 打包配置文件,暫命名為
webpack.prod.js
當(dāng)然氧腰,需要把 dev
或 prod
中的配置和 base
的配置合并起來(lái)枫浙,安裝個(gè)webpack-merge
吧。
然后配置一下最熟悉的腳本運(yùn)行環(huán)節(jié)吧容贝。通過(guò)--config
來(lái)對(duì)標(biāo)配置文件自脯,通cross-env
設(shè)置環(huán)境變量
"dev": "cross-env NODE_ENV=dev webpack-dev-server --config script/webpack.dev.js",
"build": "cross-env NODE_ENV=prod webpack --config script/webpack.prod.js"
好的,初期準(zhǔn)備工作都OK開始配置環(huán)節(jié)斤富。
開始配置
首先是webpack的出入口膏潮。出口設(shè)置為 dist 環(huán)節(jié)簡(jiǎn)單直接上代碼。
{
entry: './src/index.js',
output: {
filename: '[name].[hash:8].js',
path: rootResolve('dist'),
publicPath: '/'
},
}
順便配置下別名满力。依然可以直接上代碼
resolve: {
extensions: ['.js', '.json'],
alias: {
'@': rootResolve('src'),
'@assets': rootResolve('src/assets'),
}
}
然后是關(guān)鍵環(huán)節(jié):loader
和 plugins
關(guān)于 loader
:
- 樣式上使用
less
- 需要通過(guò)
less-loader
解析less
因?yàn)?webpack 只能讀懂js - 解析完成再通過(guò)
postcss-loader
加上瀏覽器前綴 - 再通過(guò)
css-loader
解析css代碼中的url
焕参、@import
語(yǔ)法 - 最后,通過(guò)
MiniCssExtractPlugin.loader
生成.css
文件
- 需要通過(guò)
- JS 文件使用
babel-loader
油额,關(guān)于babel
文章太多了叠纷,暫略- 順便使用
HappyPack
進(jìn)行優(yōu)化加速 - 為什么不選
thread-loader
呢? (因?yàn)槊植缓寐?tīng)- -!
怪我咯)
- 順便使用
- 其他文件潦嘶,用
url-loader
咯涩嚣。
然后 loader
配置就是這樣的
{
test: /\.less$/,
exclude: /(node_modules|bower_components)/,
loaders: [{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true,
hmr: process.env.NODE_ENV === 'dev', // 熱更新
// publicPath: '../',
}
}, 'css-loader', 'postcss-loader', 'less-loader']
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
loader: 'happypack/loader',
options: {
id: 'babel',
}
},
{
test: /\.(png|jpe?g|gif)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192,
name: 'assets/img/[hash:8].[ext]'
}
}]
}
關(guān)于插件部分,首先是配合上面 loader
的相關(guān)插件:HappyPack
和 MiniCssExtractPlugin
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css", // css 路徑
}),
new HappyPack({
id: 'babel',
loaders: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true
}
}]
})
當(dāng)然掂僵,我想知道運(yùn)行和打包的進(jìn)度: ProgressPlugin
航厚,順便弄個(gè) DefinePlugin
工程化必備插件。最后webpack生成后的代碼注入不能少了 HtmlWebpackPlugin
然后 base
文件的插件結(jié)構(gòu)是這樣的
plugins: [
new webpack.ProgressPlugin(),
new webpack.DefinePlugin({
NODE_ENV: JSON.stringify(process.env.NODE_ENV), // 當(dāng)前使用環(huán)境
VERSION: JSON.stringify('0.1.0'),
}),
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css", // css 路徑
// chunkFilename: "[id].css",
}),
new HappyPack({
id: 'babel',
loaders: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true
}
}]
}),
new HtmlWebpackPlugin({ template: './src/index.html' })
]
開發(fā)環(huán)境配置
首先開發(fā)環(huán)境 api 代理必不可少锰蓬。那么就是 devServer.proxy
了幔睬,順便再定義下開發(fā)環(huán)境端口號(hào)。
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 3333
}
目前也沒(méi)有太多事情芹扭,那么 merge 下再配個(gè) HotModuleReplacementPlugin
吧
merge(base, {
mode: 'development',
plugins: [
],
devServer: {
contentBase: rootResolve("src"),
compress: true,
port: 3333
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
})
打包環(huán)境
打包環(huán)境主要做了這幾件事情
- 打包優(yōu)化
- 分類文件
- 刪除冗余
首先是 dll
- 定義 dll 配置文件麻顶。 比如:
webpack.dll.config.js
- 需要定義要打包的庫(kù)和打包的出口
- 命名生成后的dll模塊的詳細(xì)要點(diǎn)文件
manifest.dll.json
那么 webpack.dll.config.js
內(nèi)容應(yīng)該是這樣的
{
// 你想要打包的模塊的數(shù)組
entry: {
vendor: ['three']
},
output: {
filename: '[name].dll.js',
path: distResolve('dll'), // 打包后文件輸出的位置
library: '[name]_library'
// 這里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
},
plugins: [
new webpack.DllPlugin({
name: '[name]_library',
path: distResolve('dll/manifest.dll.json'),
context: __dirname
})
]
}
- 通過(guò)
DllReferencePlugin
+json文件
把 dll模塊的詳細(xì)要點(diǎn)告訴 webpack
在 prod
文件中添加 plugins
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require(distResolve('./dll/manifest.dll.json'))
})
- 添加腳本運(yùn)行配置
"dll": "webpack --config script/webpack.dll.config.js",
運(yùn)行下 npm run dll
舱卡,在 dist/dll
目錄下生成dll相關(guān)文件辅肾,那么 dll
配置也完成了。順便做一些清理工作轮锥,用下 CleanWebpackPlugin
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'assets', 'js', 'css', 'index.html', '*.js',
'!manifest.dll.json', '!vendor.dll.js' // 不刪除 dll 文件
],
})
然后是代碼優(yōu)化宛瞄,其實(shí)當(dāng) mode: 'production'
時(shí)已經(jīng)做了很多代碼優(yōu)化相關(guān)的事情了。(我不管,我就是要優(yōu)化 - -!
)
做一下 js的并行壓縮吧
optimization: {
minimizer: [
new TerserWebpackPlugin({
parallel: true, // 啟用并行壓縮
cache: true, // 啟用緩存
}),
new OptimizeCssAssetsPlugin({ // 壓縮css
cssProcessorOptions: {
safe: true
}
})
],
runtimeChunk: true, // 自動(dòng)拆分runtime文件
splitChunks: {
chunks: 'async',
minSize: 30000,
automaticNameDelimiter: '~',
automaticNameMaxLength: 30,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
},
}
歐耶份汗,再配置下js的打包后路徑就好了
output: { // JS 路徑
path: distResolve(),
filename: 'js/[id].[chunkhash].js',
chunkFilename: 'js/[name].[chunkhash].js'
},
最后 merge
下 base
配置。在 dev
時(shí)做過(guò)了... 省略蝴簇。
至此杯活,Webpack配置已經(jīng)大部分完成了,運(yùn)行npm run build
打包代碼熬词,1旁钧、2、3互拾。 3秒打包完成了歪今。
為什么只需要3秒呢?雖然上面的配置確實(shí)做了很多優(yōu)化颜矿,但是大部分事情都被表象迷惑了寄猩,具體為何下一章見(jiàn)。
最后
- 源碼地址 https://github.com/zhongmeizhi/three-demo
- 更多實(shí)戰(zhàn)項(xiàng)目:https://github.com/zhongmeizhi/z-ui
- 一個(gè)字一個(gè)字碼出來(lái)的文章骑疆,原創(chuàng)不易田篇,點(diǎn)個(gè)贊唄。
- 歡迎關(guān)注公眾號(hào)「前端進(jìn)階課」認(rèn)真學(xué)前端箍铭,一起進(jìn)階泊柬。