經過三個章節的學習,你已經學會搭建了一個基於webpack4的react腳手架。如果要更改配置,比如,你希望把編譯后的js文件和css文件等單獨放dist下的static目錄下,你想想,是不是有點麻煩。你要去瀏覽webpack的配置文件,找到哪些配置項,然后去更改它,我們希望有個參數配置文件,只要更改參數配置,而無需更改webpack的配置文件。
(1)在根目錄創建config文件夾,在config文件夾內新建一個index.js文件,文件內容如下:
'use strict' const path = require('path') module.exports = { dev: { assetsSubDirectory: 'static', assetsPublicPath: '/', }, build: { assetsRoot: path.resolve(__dirname, '../dist'), assetsSubDirectory: 'static', assetsPublicPath: '/', } }
我們定義了一部分配置參數,顧名思義,dev屬性下的參數配置是針對開發環境,build屬性下的參數配置是針對生產環境的。其中,assetsRoot是編譯后的文件存放根路徑,assetsSubDirectory是資源文件編譯后存放的文件夾名稱,assetsPublicPath是公共的路徑。
(2)修改webpack.base.conf.js,如下
const path = require('path'); const config=require('../config'); const APP_PATH = path.resolve(__dirname, '../app'); module.exports = { entry: { app: './app/index.js', framework: ['react', 'react-dom'], }, output: { path: config.build.assetsRoot, filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, module: { rules: [ { test: /\.js?$/, use: "babel-loader", include: APP_PATH } ] } };
注意:我們在webpack.base.conf.js內配置了filename,那么dev環境下默認使用該配置,可以刪除webpack.dev.conf.js內關於output的配置。
(3)路徑生成方法:
路徑的配置需要由assetsPublicPath和assetsSubDirectory以及具體的子路徑組成,我們寫一個公共的方法來生成路徑。無論是開發環境還是生產環境,我們都可以復用該方法。我們在build文件夾下建立一個utils.js文件。內容如下:
const path = require('path') const config = require('../config') exports.assetsPath = function (_path) { const assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory return path.posix.join(assetsSubDirectory, _path) }
(4)修改webpack.prod.conf.js
在webpack.prod.conf.js頁面頭部引入
const config=require('../config'); const utils=require('./utils');
修改output屬性的內容
output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash:16].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') },
修改plugins內的相關配置:
new CleanWebpackPlugin([config.build.assetsRoot], { allowExternal: true }), //導出css new MiniCssExtractPlugin({ filename: utils.assetsPath('css/[name].[hash].css'), chunkFilename: utils.assetsPath('css/[id].[hash].css'), }),
(5)執行編譯命令查看
npm run build
查看編譯后的文件是否放在static目錄下了。你可以修改參數配置文件,然后試試看吧。
(1)index.html HTML模板的位置
在config.js文件的dev和build參數下都配置index屬性:
index: path.resolve(__dirname, '../public/index.html'),
修改HtmlWebpackPlugin內template的值:
webpack.prod.conf.js的相關修改:
new HtmlWebpackPlugin({ template: config.build.index, inject: 'body', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, }),
webpack.dev.conf.js的相關修改:
new HtmlWebpackPlugin({ template: config.dev.index, inject: true }),
(2)增加devServer 的配置
dev環境下,啟動的端口號,代理相關,以及是否自動打開瀏覽器等等推薦可以放在參數配置文件內。
在config.js文件內增加相關配置參數:
proxyTable: {}, host: 'localhost', port: 8080, autoOpenBrowser: true,
修改webpack.dev.conf.js內的相關配置:
devServer: { host: config.dev.host, port: config.dev.port, contentBase: path.join(__dirname, '../public'), compress: true, historyApiFallback: true, hot: true, https: false, noInfo: true, open: config.dev.autoOpenBrowser, proxy: config.dev.proxyTable, }
(1)前期准備,增加部分參數配置
修改config.js內的配置:
const path = require('path') module.exports = { base: { // 是否開啟cssModule cssModule: true, // cssModule排除的目錄, 其他css庫可以放這里 cssModuleExcludePath: /public/ }, dev: { assetsSubDirectory: 'static', assetsPublicPath: '/', index: path.resolve(__dirname, '../public/index.html'), proxyTable: {}, host: 'localhost', port: 8080, autoOpenBrowser: true, // 是否生成sourceMap cssSourceMap: true, }, build: { assetsRoot: path.resolve(__dirname, '../dist'), assetsSubDirectory: 'static', assetsPublicPath: '/', index: path.resolve(__dirname, '../public/index.html'), // 是否生成sourceMap productionSourceMap: true, } }
(2) 在utils.js內增加cssLoaders和styleLoaders方法:
exports.cssLoaders = function (options) { options = options || {} let cssLoader = { loader: 'css-loader', options: { importLoaders: 1, sourceMap: options.sourceMap } } if (options.cssModule) { cssLoader.options.modules = true; cssLoader.options.localIdentName = '[local]__[hash:7]'; } const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: options.sourceMap } } function generateLoaders(loader, loaderOptions) { const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] if (loader) { loaders.push({ loader: loader + '-loader', options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) } if (options.extract) { return [MiniCssExtractPlugin.loader].concat(loaders) } else { return ['style-loader'].concat(loaders) } } return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders('less', { javascriptEnabled: true, indentedSyntax: true }), sass: generateLoaders('sass', { indentedSyntax: true }), scss: generateLoaders('sass'), stylus: generateLoaders('stylus'), styl: generateLoaders('stylus') } } exports.styleLoaders = function (options) { let output = [] const loaders = exports.cssLoaders(options) for (const extension in loaders) { const loader = loaders[extension] let loaderObj = { test: new RegExp('\\.' + extension + '$'), use: loader, } if (options.cssModule) { loaderObj.exclude = options.cssModuleExcludePath; } output.push(loaderObj) } if (options.cssModule) { options.cssModule = false const cssModuleLoaders = exports.cssLoaders(options) for (const extension in cssModuleLoaders) { const cssModuleLoader = cssModuleLoaders[extension] let cssModuleLoaderObj = { test: new RegExp('\\.' + extension + '$'), use: cssModuleLoader, } cssModuleLoaderObj.include = options.cssModuleExcludePath; output.push(cssModuleLoaderObj) } } return output }
(3) 在webpack.prod.conf.js內使用
確認是否引入了utils,如果沒有引入,在頁面上方增加代碼:
const utils=require('./utils');
修改 module內的rules屬性:
rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true, cssModule:config.base.cssModule, cssModuleExcludePath:config.base.cssModuleExcludePath })
執行編譯查看:
npm run build
(4) 在webpack.dev.conf.js內使用
確認是否引入了utils,如果沒有引入,在頁面上方增加代碼:
const utils=require('./utils');
修改 module內的rules屬性:
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true, cssModule:config.base.cssModule, cssModuleExcludePath:config.base.cssModuleExcludePath })
執行dev命令試試看
npm run dev
下一節會對 如果對編譯后的文件進行gzip壓縮,如何讓開發環境的控制台輸出更加高逼格,如何更好的對編譯后的文件進行bundle分析等問題展開討論。