- 最近有一個項目,考慮到要進行 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
,點擊這裏。