前言
前端时间写了个多入口的 webpack4 的配置 ( multiple_page_webpack ),后面新开了下目录,将其改为打包 vue 的配置
本次 webpack4 的配置源码:https://github.com/VintageLin/webpack4ForVue
改造过程
1. 先将上篇文章中的 mutiple_page_webpack 的入口改成单一入口,删除寻找入口文件的 js,取消对其的引用
2. 删除无用的文件,根据 webpack 的配置,入口放在 src 文件目录下,目录结构变为如下图
3. 安装 vue,vue-loader,vue-template-compiler,因为要使用到 vue-router,所以也一并安装
npm install -D vue-loader vue-template-compiler
npm install -S vue
npm install -S vue-router
4. 安装完后,配置 webpack4。按照 vue 官网的文档做法
然后增加 vue-loader 的配置,查阅官网可得:
根据文档,webpack 的通用配置改为如下:
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const htmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, '../build'),
filename: 'js/[name].[hash].js',
chunkFilename: 'js/[name].js'
},
// 控制台打印输出配置
stats: {
entrypoints: false,
chunks: false,
children: false,
chunkModules: true,
modules: false
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(jpg|jpeg|png|gif)$/,
loader: 'url-loader',
options: {
name: 'images/[name].[hash].[ext]',
limit: 10000
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader?cacheDirectory=true', 'eslint-loader']
},
{
test: /\.html$/,
loader: 'html-loader'
}
]
},
resolve: {
// 模块别名,方便import
alias: {
'@': path.resolve(__dirname, '../src/'),
'vue$': 'vue/dist/vue.esm.js'
},
// 自动解析扩展名
extensions: ['.js', '.json', '.vue']
},
plugins: [
// 页面模板
new VueLoaderPlugin(),
new htmlWebpackPlugin({
template: './src/index.html',
chunks: './src/index.js'
})
]
}
开发环境 config.DEV.js 的配置如下:
const merge = require('webpack-merge')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const chalk = require('chalk')
const log = console.log
const webpackUniversalConfig = require('./webpack.config.js')
const CONSTANT = require('./config.CONSTANT')
const config = {
mode: 'development',
devServer: {
compress: true, // gzip压缩
port: CONSTANT.INITIAL_PORT, // 端口
hot: true, // hot reload
overlay: true, // 出现编译器错误或警告时,在浏览器中显示全屏覆盖层
stats: 'minimal',
quiet: true,
host: CONSTANT.HOST
},
devtool: 'source-map',
plugins: [],
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
}
],
}
]
}
}
module.exports = new Promise((resolve, reject) => {
// 端口查找
portfinder.getPort({
port: CONSTANT.INITIAL_PORT, // 起始
stopPort: CONSTANT.STOP_PORT // 结束
}, function (err, res) {
if (err) {
log(chalk.red('在当前设定的区间无可使用的端口!'))
process.exit()
} else {
log(chalk.green('当前DEV可运行的端口:', res))
config.devServer.port = res
config.plugins.push(new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: [`当前项目运行在 http://${CONSTANT.HOST}:${res}`]
}
}))
// 合并设置
const config_DEV = merge(config, webpackUniversalConfig)
resolve(config_DEV)
}
})
})
生产打包配置 config.PROD.js 如下:
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const merge = require('webpack-merge')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackUniversalConfig = require("./webpack.config.js")
const config = {
mode: 'production',
output: {
// 公共目录定位到当前文件夹下
publicPath: './'
},
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'vue-style-loader',
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
hmr: process.env.NODE_ENV === 'development',
},
},
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
}
],
}
]
},
performance: {
hints: false
},
plugins: [
// 每次打包前清空打包目标文件夹
new CleanWebpackPlugin(),
// 抽离css到单独文件
new MiniCssExtractPlugin({
filename: 'css/[name].css?[hash]',
chunkFilename: '[id].[hash].css',
ignoreOrder: false
})
],
optimization: {
minimizer: [
// js压缩
new UglifyWebpackPlugin({
parallel: 4
}),
// css压缩
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css/, // 需要优化压缩的文件名
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
})
],
// 代码拆分
splitChunks: {
cacheGroups: {
// 打包node_modules中的文件
vendor: {
name: "vendor",
test: /[\\/]node_modules[\\/]/,
chunks: "all",
priority: 10
}
}
}
}
}
const config_PROD = merge(config, webpackUniversalConfig)
module.exports = config_PROD
发现的问题
以上代码是更正过的!在我刚改为打包 vue 的配置的时候,发现了个问题,就是每次保存样式的时候,样式都不自动热更新。在开发者工具中查看了之后,发现它引用了一个 css 文件,切控制台显示无任何模块被更新,没有请求最新的 css 文件。在以前使用 vue 脚手架生成的项目中,每次保存文件,都是热更新的,也没有去引用这种提取出来页面的样式的 css。
解决办法:
发现增加了
发现问题所在之处后,觉得应该是 mini-css-extract-plugin 惹的锅,是它导致了样式不能热更新,导致新样式没有直接注入到js代码中去。因为热更新只支持 js 的 module,也就是说必须转换成js读取的。
观察热更新的文件内容,也可以发现热更新内容中没有 css 过来,都被打包到 css 文件中了,只能刷新页面实现样式最新。破案了!
根据上面的发现,将 webpack.config.js 和 config.DEV.js 中的配置去除 mini-css-extract-plugin 相关的配置,启动后,修改 vue 的文件并保存,发现热更新的文件中有了最新的 css 样式过来了。百度搜索了下解决办法,目前就看到有人提到这个问题,也是类似的解决办法,只不过他是 webpack3,需要去除的是 extract-text-webpack-plugin ,问题地址在此: https://segmentfault.com/q/1010000007574764
所以,在开发环境并不需要这个提取 css 到文件的插件,在打包到文件的时候才需要用到这个插件。
基本上改造成 vue 的 webpack4 打包配置也就这么搞定了,其他的就是 src 目录下的 vue 对 vue-router 的使用或者 vuex 的使用了。
前后呼应,源码在这:https://github.com/VintageLin/webpack4ForVue 欢迎大家指出错误