简介
这是在创建项目后,原封不动的改成webpack5
期间可能还要安装全局的webpack、webpack-dev-server、webpack-cli等没有配备的库
1.build.js
'use strict'
require('./check-versions')()
process.env.NODE_ENV = 'production'
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
})
2.utils.js
'use strict'
const path = require('path')
const config = require('../config')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory;
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
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
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return [
{
loader: MiniCssExtractPlugin.loader,
}
].concat(loaders)
} else {
return [
{
loader: 'style-loader'
}
].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
// sass: generateLoaders('sass', { indentedSyntax: true }),
// scss: generateLoaders('sass'),
// stylus: generateLoaders('stylus'),
// styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension];
// console.log("css-loader", loader)
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
3.webpack.base.conf.js
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const webpack = require('webpack')
const vueLoaderConfig = require('./vue-loader.conf')
const { VueLoaderPlugin } = require('vue-loader');
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
vue$: 'vue/dist/vue.js',
'@': resolve('src'),
}
},
module: {
rules: [
{
test: /\.vue$/,
use: {
loader: 'vue-loader'
}
},
{
test: /\.tsx?$/,
exclude: resolve('node_modules'),
use: [
{
loader: 'babel-loader'
},
{
loader: "ts-loader",
options: { appendTsxSuffixTo: [/\.vue$/], transpileOnly: true }
}
]
},
{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: resolve('node_modules'),
include: resolve('src')
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 10kb
}
},
generator: {
filename: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
},
node: {
global: false
},
plugins: [
new VueLoaderPlugin(),
new webpack.ProvidePlugin({
jQuery: 'jquery',
$: 'jquery'
}),
// new webpack.DllReferencePlugin({
// context: __dirname,
// manifest: path.resolve(__dirname, './vendors.manifest.json')
// })
],
cache: {
// 将缓存类型设置为文件系统,默认为memory
type: 'filesystem',
buildDependencies: {
// 当构建依赖的config文件(通过 require 依赖)内容发生变化时,缓存失效
config: [__filename],
// 如果你有其他的东西被构建依赖,你可以在这里添加它们
},
},
}
4.webpack.dev.conf.js
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const { merge } = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
mode: 'development',
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
devtool: config.dev.devtool,
devServer: {
// clientLogLevel: 'warning',
// historyApiFallback: {
// rewrites: [
// { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
// ],
// },
// hot: true,
// contentBase: false,
// compress: true,
// host: HOST || config.dev.host,
// port: PORT || config.dev.port,
// open: config.dev.autoOpenBrowser,
// overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false,
// publicPath: config.dev.assetsPublicPath,
// proxy: config.dev.proxyTable,
// quiet: true,
// watchOptions: {
// poll: config.dev.poll,
// }
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: 'body',
scriptLoading: 'blocking',
minify: {
removeComments: true
}
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
globOptions: {
dot: true,
gitignore: true,
ignore: ['.*'],
}
},
]
})
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
process.env.PORT = port
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined
}))
resolve(devWebpackConfig)
}
})
})
5.webpack.prod.conf.js
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const env = require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
mode: "production",
module: {
rules: utils.styleLoaders({
sourceMap: false,
extract: true,
usePostCSS: true
})
},
devtool: config.build.devtool,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
clean: true
},
optimization: {
minimize: true,
minimizer: [
new TerserWebpackPlugin(),
new OptimizeCSSPlugin(),
],
runtimeChunk: { name: 'runtime' },
concatenateModules: true,
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all',
priority: -10
},
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
name: 'async-vendors'
}
},
},
moduleIds: 'deterministic'
},
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
chunkFilename: utils.assetsPath('css/[name].[contenthash].css')
}),
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
scriptLoading: 'blocking',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'auto'
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
globOptions: {
dot: true,
gitignore: true,
ignore: ['.*'],
}
},
]
})
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin');
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
filename: '[path][base].gz[query]',
algorithm: 'gzip',
test: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
6.dev.env.js
'use strict'
const {merge} = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
7.package.json
记得npm全局安装cross-env
{
"name": "pic",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "hwx <8355790+hwxhwx2001@user.noreply.gitee.com>",
"private": true,
"scripts": {
"dev": "npx webpack serve --config build/webpack.dev.conf.js --color --progress",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.conf.js",
"start": "npm run dev"
},
"dependencies": {
"axios": "^0.27.2",
"chalk": "^4.0.0",
"element-ui": "^2.15.8",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.6.0",
"node-less": "^1.0.0",
"node-sass": "^7.0.1",
"style-loader": "^3.3.1",
"vue": "^2.5.2",
"vue-cropper": "^0.5.8",
"vue-router": "^3.0.1",
"vuex": "^3.6.2",
"webpack": "^5.72.0"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.2.33",
"autoprefixer": "^10.4.7",
"babel-core": "^6.26.3",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-jest": "^28.1.0",
"babel-loader": "^7.1.2",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-2": "^6.24.1",
"babel-register": "^6.26.0",
"chalk": "^4.0.0",
"chromedriver": "^101.0.0",
"copy-webpack-plugin": "^9.1.0",
"cross-env": "^7.0.3",
"cross-spawn": "^7.0.3",
"css-loader": "^6.7.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^6.2.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-webpack-plugin": "^5.5.0",
"jest": "^28.1.0",
"jest-serializer-vue": "^2.0.2",
"mini-css-extract-plugin": "^2.6.0",
"nightwatch": "^2.1.4",
"node-notifier": "^10.0.1",
"node-sass": "^7.0.1",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"ora": "^5.1.0",
"portfinder": "^1.0.28",
"postcss-import": "^14.1.0",
"postcss-loader": "^6.2.1",
"postcss-url": "^10.1.3",
"progress-bar-webpack-plugin": "^2.1.0",
"rimraf": "^3.0.2",
"selenium-server": "^3.141.59",
"semver": "^7.3.7",
"shelljs": "^0.8.5",
"terser-webpack-plugin": "^5.3.1",
"thread-loader": "^3.0.4",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"vue": "^3.2.33",
"vue-jest": "^3.0.7",
"vue-lazyload": "^1.3.3",
"vue-loader": "^15.9.8",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.72.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0",
"webpack-merge": "^5.8.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}