- 最近有一個項目,考慮到要進行 SEO,因此要作成多頁面應用。爲了保證開發速度和開發效率,因此決定使用 webpack 作一套模塊化配置方案。
- 下面主要針對一些重要的點提供思路,並不做詳解。完整的代碼,我會放在 github(項目地址)上供你們參考,若是有優化的地方,請在評論區指點出來,。
|-- build webpack 配置
| |-- utils.js 處理 webpack 配置的公共方法
| |-- webpack.base.conf.js 公共配置
| |-- webpack.dev.conf.js 開發環境配置
| |-- webapck.prod.conf.js 生產環境配置
| |-- webpack.rules.conf.js 文件處理規則
|-- dist 存放變異後文件
|-- |
|-- src 源文件
| |-- assets
| |-- pages
| | |-- index 首頁
| | | |-- index.html 首頁模板
| | | |-- index.js 首頁入口文件
| htmlarrary.js 頁面配置文件
複製代碼
多頁面,首先最重要的就是處理多個 html 模板和對應的多個入口文件。css
在項目根目錄建立一個 htmlarrary.js
,用來存儲頁面配置:html
// htmlarrary.js
module.exports = [
{
_html: 'index',
title: '首頁',
chunks: ['index', 'manifest', 'vendors'] // 頁面用到的vendor模塊
},
{
_html: 'login',
title: '登陸',
chunks: ['login']
}
]
複製代碼
而後在 /build/utils.js
建立 getHtmlArray
方法,用來自動生成多個模板的配置:node
// /build/utils.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const htmlArray = require('../htmlarray.js')
exports.getHtmlArray = function (moduleExportsPlugins) {
// 根據模板配置生成 HtmlWebpackPlugin 須要的配置
const getHtmlConfig = function (name, chunks, title) {
return {
template: `./src/pages/${name}/index.html`,
filename: `./${name}.html`,
favicon: './src/assets/images/public/favicon.ico',
title,
inject: true,
hash: true, // 開啓hash
chunks, // 頁面要引入的包
minify: process.env.NODE_ENV === 'development' ? false : {
removeComments: true, // 移除HTML中的註釋
collapseWhitespace: true, // 摺疊空白區域 也就是壓縮代碼
removeAttributeQuotes: true, // 去除屬性引用
},
};
};
// 循環建立模板配置
htmlArray.forEach((element) => {
const { _html, chunks, title } = element
moduleExportsPlugins.push(new HtmlWebpackPlugin(getHtmlConfig(_html, chunks, title)))
})
}
複製代碼
在 webpack.base.conf.js
中經過 getHtmlArray
添加多頁面引擎配置:webpack
const { getHtmlArray } = require('./utils.js')
module.exports = {
// ... 相關配置
}
getHtmlArray(module.exports.plugins)
複製代碼
在 /build/utils.js
建立 getEntry
方法,用來自動生成入口文件的配置:git
// /build/utils.js
const glob = require('glob')
exports.getEntry = function () {
const entry = {}
// 讀取src目錄全部page入口
glob.sync('./src/pages/*/*.js').forEach((name) => {
const start = name.indexOf('src/') + 4;
const end = name.length - 3;
const eArr = [];
const n = name.slice(start, end).split('/')[1];
eArr.push(name);
eArr.push('@babel/polyfill'); // 引入這個,是爲了用async await,一些IE不支持的屬性可以受支持,兼容IE瀏覽器用的
entry[n] = eArr;
})
return entry;
}
複製代碼
在 webpack.base.conf.js
中經過 getEntry
添加多入口配置:github
// webpack.base.conf.js
const { getEntry } = require('./utils.js')
module.exports = {
entry: getEntry(),
}
複製代碼
JS 方面,咱們通常有如下需求:web
針對以上需求,咱們來配置一會兒 rules,而且作一下延伸:chrome
// webpack.rules.conf.js
module.exports = [
{
test: /\.(js|ts)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
targets: {
chrome: '58',
ie: '8'
},
corejs: 2
}]
]
}
},
{
loader: 'ts-loader'
},
{
loader: 'eslint-loader',
options: {
cache: true // 優化打包速度
}
}
]
}
]
複製代碼
在生產環境,咱們須要對 js 文件進行壓縮,公共代碼抽離,因此還須要在 webpack.prod.conf.js
中這樣去優化一下:typescript
// webpack.prod.conf.js
cconst merge = require('webpack-merge')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const baseConfig = require('./webpack.base.conf.js')
const prodConfig = {
optimization: {
minimizer: [
// 會致使 sourcemap 消失
new UglifyJsPlugin({
uglifyOptions: ({
compress: false
})
}),
new OptimizeCSSAssetsPlugin({})
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: { // 抽離第三方插件
test: /[\\/]node_modules[\\/]/, // 指定是node_modules下的第三方包
name: 'vendors',
priority: -10 // 抽取優先級
},
utilCommon: { // 抽離自定義
name: 'common',
minSize: 0, // 將引用模塊分離成新代碼文件的最小體積
minChunks: 2, // 表示將引用模塊如不一樣文件引用了多少次,才能分離生成新chunk
priority: -20
}
}
},
// optimization.runtimeChunk 就是告訴 webpack 是否要把這部分單獨打包出來,來優化緩存問題
runtimeChunk: {
name: 'manifest'
}
}
}
module.exports = merge(baseConfig, prodConfig)
複製代碼
CSS 方面,咱們通常有如下需求:瀏覽器
針對以上需求,咱們來配置一會兒 rules,而且作一下延伸:
// webpack.rules.conf.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = [
{
test: /\.scss$/i,
use: [
Object.assign(
// 生產環境壓縮 css 須要使用 MiniCssExtractPlugin.loader 代替 style-loader
{ loader: process.env.NODE_ENV === 'production' ? MiniCssExtractPlugin.loader : 'style-loader' },
// 解決編譯後 css 圖片不能正常顯示的問題
process.env.NODE_ENV === 'production' ? { options: { publicPath: '../' } } : {}
),
'css-loader',
'sass-loader',
'postcss-loader'
]
}
]
複製代碼
在生產環境,咱們須要對 css 文件進行壓縮,因此還須要在 webpack.prod.conf.js
中這樣去優化一下:
// webpack.prod.conf.js
cconst merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const baseConfig = require('./webpack.base.conf.js')
const prodConfig = {
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin({})
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFileName: '[id].[contenthash:8].css'
}),
]
}
module.exports = merge(baseConfig, prodConfig)
複製代碼
images 方面,咱們通常有如下需求:
針對以上需求,咱們來配置一會兒 rules,而且作一下延伸:
// webpack.rules.conf.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = [
{
test: /\.html$/,
use: [
// 若是 img 標籤的 src 爲空的話,就報錯 xxxHTMLLINKxxx0.
{
loader: 'html-loader',
}
]
},
{
test: /\.(png|jpg|gif|ico)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name].[hash:8].[ext]',
limit: 30000,
outputPath: './images'
}
}
]
}
]
複製代碼
// webpack.dev.conf.js
const devConfig = {
devServer: {
open: true,
host: '0.0.0.0',
port: 2000,
useLocalIp: true,
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
}
複製代碼
這樣智能啓動 css 熱更新,若是須要 js 熱更新,須要添加一段代碼,請自行查找 官網文檔。
TS2688: Cannot find type definition file for 'unist'.
說明須要安裝依賴 @types/unist
,其餘相似報錯同樣,這是 typescript@2.0
更換 types 支持方式致使的報錯。publicPath
,點擊這裏。