这是Webpack+React系列配置过程记录的第五篇。其余内容请参考:css
这篇文章的主要内容包括:html
在开始以前又要修改一下项目的目录结构,主要是为了抽离前端代码和测试用的服务器共同使用到的一些配置,以及为拆分dev和prod环境的配置作准备。因为改动内容比较多,也没有什么须要特别注意的知识点,故不细述,有问题参考后面给出的源码便可。前端
在css-loader的配置上作了一些改动。原来是使用-m后缀区分要不要对CSS文件进行模块化处理,此次改动主要抛弃这种作法,配置了当前项目的全部CSS文件启用模块化处理,这样能够在js文件中访问css文件中定义的类。结合css-loader的文档和个人使用体验,发现这样作基本知足了目前我所碰到的场景。而针对第三方依赖(如:antd)使用的css/less文件,默认不启用模块化。否则可能致使打包后的网页没法正确显示第三方库的样式。react
接下来开始正题。webpack
npm安装这几个依赖:git
npm i -D less-loader less url-loader file-loader postcss-loader
在webpack.config.js文件中添加这几个loader的配置。这里我对url-loader和file-loader的传参方式使用的仍是旧版本的方式,仅是由于看起来比较顺眼。github
... { // 当前项目的less文件,启用CSS modules test: /\.less$/, include: [config.srcPath], exclude: [config.libPath], use: ExtractTextPlugin.extract({ fallback: "style-loader", use: [ { loader: 'css-loader', options: { modules: true, importLoaders: 3, localIdentName: '[path][name]-[local]-[hash:base64:5]' } }, { loader: path.resolve(__dirname, '..', 'loader/less-css-modules-assets-fix-loader.js') }, { loader: 'postcss-loader', options: { plugins: [ require('autoprefixer')() ] } }, { loader: 'less-loader' } ] }) }, ... { test: /\.woff(\?.*)?$/, use: 'url-loader?prefix=fonts/&name=[name]_[hash:8].[ext]&limit=10000&mimetype=application/font-woff' }, { test: /\.woff2(\?.*)?$/, use: 'url-loader?prefix=fonts/&name=[name]_[hash:8].[ext]&limit=10000&mimetype=application/font-woff2' }, { test: /\.otf(\?.*)?$/, use: 'file-loader?prefix=fonts/&name=[name]_[hash:8].[ext]&limit=10000&mimetype=font/opentype' }, { test: /\.ttf(\?.*)?$/, use: 'url-loader?prefix=fonts/&name=[name]_[hash:8].[ext]&limit=10000&mimetype=application/octet-stream' }, { test: /\.eot(\?.*)?$/, use: 'file-loader?prefix=fonts/&name=[name]_[hash:8].[ext]' }, { test: /\.svg(\?.*)?$/, use: 'url-loader?prefix=fonts/&name=[name]_[hash:8].[ext]&limit=10000&mimetype=image/svg+xml' }, { test: /\.(png|jpg|jpeg)$/, use: 'url-loader?limit=8192' } ...
这样就能够在项目中使用less了。你可能会注意到我在配置中增长了这样一行配置:web
loader: path.resolve(__dirname, '..', 'loader/less-css-modules-assets-fix-loader.js')
这是一个自定义的loader,是为了解决less-loader在启用模块化时没法正确解析到在less文件中引用的外部地址的问题。请参考less-loader的这个issue。正则表达式
自定义的loader代码很简单,执行正则表达式替换:npm
module.exports = function (content) { return content.replace(/url\(('|")*(\.\/)*(.+?)('|")*\)/g, 'url(./$3)').replace(/\.\/((https?|ftp):\/\/)/, '$1'); };
前面在进行代码分割的时候留下了一个坑:须要在index.html中手动引入指定名称的JS文件和CSS文件。一方面这样作比较烦,另外一方面对发布和更新不利(缓存致使的各类问题)。
这里使用HtmlWebpackPlugin插件解决这个问题。安装方法是:
npm i -D html-webpack-plugin
配置上主要该了这些内容:
... // 引入插件 const HtmlWebpackPlugin = require('html-webpack-plugin'); ... // 配置上下文到项目根目录,这样可使用相对根目录的路径访问其余文件,以下面的'./template/index.html' context: config.rootPath, // 修改output output: { filename: '[name].[hash:8].js', chunkFilename: 'chunk.[id].[hash:8].js', publicPath: config.publicPath }, ... // 在plugins节点添加 new HtmlWebpackPlugin({ template: './template/index.html' }), new ExtractTextPlugin({ filename: 'styles.[contenthash].css' }),
能够看到我吧output的filename和chunkFilename的命名方式都改为攻台配置的了,故生成的将会是形如main.1.xxxx.js的js文件。styles.css也加入了hash后缀。
在项目根目录下建一个模板‘/template/index.html',内容比之前的index.html更简单:
<html> <head> <title>React Webpack Configuration Demo</title> </head> <body> <p>Hello world</p> <div id='main'></div> </body> </html>
删除掉原来的index.html文件吧,这是访问咱们的网页就能够看到这样的内容:
它会自动搜索到须要的外部依赖,而且以正确的顺序加载它们。
这里我尚有个疑问: index.html这个文件每次都会获取到最新的内容吗?浏览器对它有缓存吗?根据看到的结果看应该没有,否则js文件的更新就不会被正确加载了。那若是没有被缓存又是为何呢?,webpack有经过哪一种方式处理吗?
我使用比较简单的方式拆分开发环境和生成环境的配置,分别使用不一样的配置文件就好了。
把原来开发用的的webpack.config.js改为webpack.dev.config.js,并备份一份命名为webpack.prod.config.js。修改package.json和server中对配置文件的引用。
而后针对生成环境的配置文件作一些修改,主要涉及导出目录、代码混淆、去除冗余代码等相关配置。用到了如下插件:
最后改了一下package.json中的scripts:
这里就不贴出详细代码了,看源码吧。