前言
前端時間寫了個多入口的 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 歡迎大家指出錯誤