一、Webpack简介
Webpack是一个打包工具,可以把JS、CSS、Node Module、Coffeescrip、SCSS/LESS、图片等都打包在一起,因此,现在几乎所有的SPA项目、JS项目都会用到Webpack。
官网:https://webpack.js.org
GitHub为https://github.com/webpack/ webpack
二、创建基于Webpack的Vue2.7.js项目
Webpack+Vue.js的方式来做项目的,这样才可以做到“视图”“路由”“component”等的分离,以及快速打包、部署及项目上线。
1. Webpack 的相关命令,以及项目常用到的命令,我全部放这里,请务必按照版本安装!!!
"cross-env": "^7.0.2",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.70.0",
"webpack-dev-server": "^4.7.4"
"compression-webpack-plugin": "^9.2.0",
"css-loader": "^4.1.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"is-glob": "^4.0.3",
"monaco-editor": "^0.27.0",
"monaco-editor-webpack-plugin": "^4.2.0",
"process": "^0.11.10",
"style-loader": "^3.3.1",
"stylus-loader": "^6.2.0",
"vue-loader": "^15.11.1",
"vue-style-loader": "^4.1.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.10.0",
"webpack-merge": "^5.8.0",
"webpackbar": "^5.0.2"
"cross-env": "^7.0.2",
package.json代码:
"scripts": {
"build:private": "cross-env CONFIG_ENV=private webpack --config build/webpack.prod.js",
"start:private": "cross-env CONFIG_ENV=private webpack-dev-server --open --hot --config ./build/webpack.dev.js"
},
2. 文件配置
看下文件目录结构:
1)build/config.js文件:
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
let env
switch (process.env.CONFIG_ENV) {
case 'local':
env = require('../config/local.env')
break
case 'dev':
env = require('../config/dev.env')
break
case 'stage':
env = require('../config/stage.env')
break
case 'pro':
env = require('../config/prod.env')
break
case 'private':
env = require('../config/private.env')
break
default:
break
}
module.exports = {
shouldAnalyzerBundle: false,
shouldSplitChunks: false,
shouldGzipResource: false,
htmlWebpackConfig: {
// author: 'AnbanTech@FrontendTeam',
// license: 'Copyright © 2019-2022 Anban Inc. All Rights Reserved. 安般科技.',
title: '报告'
// keywords: 'webpack, vue',
// descritpion: 'learn how to config webpack to build vue project'
}
}
2)build/webpack.base.js文件:(重点分析)
const path = require('path')
const { resolve } = path
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { htmlWebpackConfig, shouldSplitChunks } = require('./config')
const WebpackBar = require('webpackbar')
const { VueLoaderPlugin } = require('vue-loader')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const isDev = process.env.NODE_ENV !== 'production'
function genereateAssetsLoader(shouldSplitChunks) {
if (shouldSplitChunks) {
return [
{
test: /\.(woff|woff2|eot|otf|ttf)$/,
type: 'asset',
generator: {
filename: 'font/[hash][ext][query]'
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext][query]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: 'media/[hash][ext][query]'
}
}
]
} else {
return [
{
test: /\.(woff|woff2|eot|otf|ttf)$/,
type: 'asset/inline'
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset/inline'
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset/inline'
}
]
}
}
module.exports = {
target: 'web',
stats: {
chunks: false,
chunkModules: false,
modules: false,
children: false,
timings: false,
assetsSort: 'name',
performance: false
},
entry: {
app: resolve('src/main.ts')
},
output: {
path: resolve('dist'),
filename: shouldSplitChunks ? 'lib/[name].[chunkhash:8].js' : 'lib/bundle.js',
publicPath: './',
clean: true
},
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'@': path.resolve('src'),
vue$: 'vue/dist/vue.esm.js'
}
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
transpileOnly: true
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
options: {
cacheDirectory: true
},
exclude: /node_modules/
},
{
test: /\.md/,
type: 'asset/source'
},
{
test: /\.styl(us)?$/,
use:
!shouldSplitChunks || isDev
? ['vue-style-loader', 'css-loader', 'stylus-loader']
: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader']
},
{
test: /\.css$/,
use:
!shouldSplitChunks || isDev
? ['vue-style-loader', 'css-loader']
: [MiniCssExtractPlugin.loader, 'css-loader']
}
].concat(genereateAssetsLoader(shouldSplitChunks))
},
plugins: [
new MonacoWebpackPlugin({
languages: ['c']
}),
new VueLoaderPlugin(),
new HtmlWebpackPlugin(
Object.assign({}, htmlWebpackConfig, {
filename: 'index.html',
title: 'webpack测试',
template: path.resolve('public/index.html'),
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
removeComments: true,
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
minifyCSS: true,
minifyJS: true,
minifyURLs: true,
useShortDoctype: true
}
})
),
shouldSplitChunks &&
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css'
}),
new CopyWebpackPlugin({
patterns: [
{
from: resolve('public'),
globOptions: {
ignore: ['**/index.html', '**/.DS_Store']
}
},
{
from: path.resolve(__dirname, '../static'),
to: 'static',
globOptions: {
ignore: ['.*']
}
}
]
}),
new WebpackBar({
name: '正在打包',
color: '#fa8c16'
}),
new FriendlyErrorsWebpackPlugin({
clearConsole: true
}),
// new BundleAnalyzerPlugin({
// analyzerHost: '127.0.0.1',
// // 将在“服务器”模式下使用的端口启动HTTP服务器。
// analyzerPort: 8888,
// // 路径捆绑,将在`static`模式下生成的报告文件。
// // 相对于捆绑输出目录。
// reportFilename: 'report.html',
// defaultSizes: 'parsed',
// // 在默认浏览器中自动打开报告
// openAnalyzer: true,
// // 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
// generateStatsFile: false,
// // 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
// // 相对于捆绑输出目录。
// statsFilename: 'stats.json',
// // stats.toJson()方法的选项。
// // 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
// // 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
// statsOptions: null,
// logLevel: 'info' // 日志级别。可以是'信息','警告','错误'或'沉默'。
// })
].filter(Boolean)
}
2)build/webpack.dev.js文件:(重点分析)
const webpack = require('webpack')
const path = require('path')
const { default: merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base')
const config = require('./config')
let env
switch (process.env.CONFIG_ENV) {
case 'local':
env = require('../config/local.env')
break
case 'dev':
env = require('../config/dev.env')
break
case 'stage':
env = require('../config/stage.env')
break
case 'pro':
env = require('../config/prod.env')
break
case 'private':
env = require('../config/private.env')
break
default:
break
}
module.exports = merge(baseWebpackConfig, {
mode: 'development',
devtool: 'eval-cheap-module-source-map',
cache: true,
devServer: {
static: false,
devMiddleware: {
publicPath: '/'
},
historyApiFallback: {
rewrites: [{ from: /.*/, to: path.posix.join('/', 'index.html') }]
},
hot: true,
compress: true,
host: 'localhost',
// 配置开发服务器的端口,默认为8080
port: 3000,
open: true,
proxy: {
'/Arrgemnt': {
target: 'http://192.168.5.32:8031',
// target: 'http://192.168.50.94:9050',
changeOrigin: true
},
'/files': {
target: 'http://192.168.5.32:21101',
// target: 'http://192.168.50.94:9050',
changeOrigin: true,
pathRewrite: { '^/files': '' }
},
'/yh': {
target: 'http://192.168.5.57:9050',
// target: 'http://192.168.50.94:9050',
changeOrigin: true
},
'/yh/analysis': {
target: 'http://192.168.5.57:9050',
ws: true,
changeOrigin: true
},
'/abfuzz/': {
target: 'http://192.168.5.57:21101',
changeOrigin: true
},
},
client: {
logging: 'warn',
overlay: false,
progress: true,
reconnect: true
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
new webpack.ProvidePlugin({
process: require.resolve('process/browser')
})
]
})
3)build/webpack.prod.js文件:
const webpack = require('webpack')
const { default: merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base')
const CompressionPlugin = require('compression-webpack-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const { shouldAnalyzerBundle, shouldGzipResource, shouldSplitChunks } = require('./config')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
let env
switch (process.env.CONFIG_ENV) {
case 'local':
env = require('../config/local.env')
break
case 'dev':
env = require('../config/dev.env')
break
case 'stage':
env = require('../config/stage.env')
break
case 'pro':
env = require('../config/prod.env')
break
case 'private':
env = require('../config/private.env')
break
default:
break
}
console.log('process.env.CONFIG_ENV:', process.env.CONFIG_ENV)
module.exports = merge(baseWebpackConfig, {
mode: 'production',
devtool: 'nosources-source-map', // production
cache: false,
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
new webpack.ProvidePlugin({
process: require.resolve('process/browser')
}),
shouldGzipResource &&
new CompressionPlugin({
filename: '[path][base].gz',
algorithm: 'gzip',
test: /\.(js|css)$/
}),
shouldAnalyzerBundle &&
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',
analyzerPort: 8889,
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
})
].filter(Boolean),
optimization: shouldSplitChunks
? {
runtimeChunk: true,
minimize: true,
minimizer: [`...`, new CssMinimizerPlugin()],
splitChunks: {
chunks: 'all',
minChunks: 1,
maxInitialRequests: 6,
maxAsyncRequests: 6,
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
: {}
})
4)config/dev.env.js文件:
'use strict'
const { default: merge } = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '"user-test.cosec.tech"',
BASE_IP: '"47.100.28.180"',
CONFIG_ENV: '"dev"'
})
5)config/local.env.js文件:
'use strict'
const { default: merge } = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '""',
BASE_IP: '""',
CONFIG_ENV: '"local"'
})
6)config/poc.env.js文件:
'use strict'
const { default: merge } = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '""',
BASE_IP: '""',
CONFIG_ENV: '"private"'
})
7)config/private.env.js文件:
const { default: merge } = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '""',
BASE_IP: '""',
CONFIG_ENV: '"private"'
})
8)config/prod.env.js文件:
'use strict'
module.exports = {
NODE_ENV: '"development"',
BASE_API: '"www.fuzzing.tech"',
BASE_IP: '"43.248.189.190"',
CONFIG_ENV: '"pro"'
}
9)config/stage.env.js文件:
'use strict'
module.exports = {
NODE_ENV: '"development"',
BASE_API: '"user-stage.cosec.tech"',
BASE_IP: '"47.101.189.106"',
CONFIG_ENV: '"stage"'
}
9)public/index.vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link type="image/x-icon" rel="shortcut icon" href="data:;">
<link type="image/x-icon" rel="shortcut icon" href="../logo.png">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<meta name="author" content="<%= htmlWebpackPlugin.options.author %>">
<meta name="license" content="<%= htmlWebpackPlugin.options.license %>">
<meta name="description" content="<%= htmlWebpackPlugin.options.descritpion %>">
<meta name="keywords" content="<%= htmlWebpackPlugin.options.keywords %>">
<script src=./lib/data.js></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
10) static 文件下有图片昂;
3.运行命令和打包命令:
npm run start:private
npm run build:private
完结撒花✿✿ヽ(°▽°)ノ✿
其实我写的过程,不断地出现报错,坚持住,不断地解决掉!!
当前配置有些冗余的代码文件,后续还需要优化
代码放在了gitee上: git@gitee.com:cathyli2021/vue2.7_webpack.git