vue 项目 webpack 打包配置
简介
了解完单个webpack的配置之后,我们来总结一下,一个 vue 项目需要的webpack配置的通用方案
本文从零开始,搭建一个 vue 项目,再给出对应的webpack配置。项目使用 vue3 + ts + less。
项目所有配置使用 webpack5,webpack 4 不分配置不支持。
核心思路
要完成一个项目的打包,可以需要做哪些事情
逐步拆解
入口、出口
入口配置使用 entry,出口配置 使用 output,这一块比较简单
{
entry: path.resolve(__dirname, '../src/main.ts'),
// 输出文件配置
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/',
},
}
更详细的配置信息可以参考:webpack 入口和出口-webfem
代码转译 - loader
loader 的详细解释可见:https://webfem.com/post/webpack-loader
vue
vue 代码的转译需要用到 vue-loader 和 vueLoaderPlugin 插件两者共同参与
css
css 和 less 在开发环境只需要 到 style-loader 即可,生产环境需要加上 MiniCssExtractPlugin.loader 做压缩
图片资源
图片资源的转译推荐使用 asset/resource,具体可以参考 https://webfem.com/post/webpack-assets
完整 loader 配置
相关解释已添加注释
{
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.ts$/, // 添加 .ts 文件的处理规则
loader: 'ts-loader', // 使用 ts-loader 编译 TypeScript
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
transpileOnly: true, // 添加此行以提高编译速度
compilerOptions: {
// 添加编译器选项
moduleResolution: 'node',
},
},
},
{
test: /\.(js|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-typescript'],
plugins: ['@vue/babel-plugin-jsx'],
},
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'assets/[name].[hash][ext]',
publicPath:
process.env.NODE_ENV === 'development'
? '/'
: `${process.env.VUE_ASSETS_URL}/`,
},
},
],
},
plugins: [
new VueLoaderPlugin(), // 必须添加 VueLoaderPlugin
],
}
代码分包
代码拆包是个根据项目情况,灵活拆分的工作。这里先不过多介绍,我们可以简单来一个配置:
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
将公共代码打包到一起
代码压缩
代码压缩详细介绍可以参考:https://webfem.com/post/webpack-assets-mini
相关配置
{
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../index.html'),
inject: true,
}), // html 拆分与压缩
new VueLoaderPlugin(), // 必须添加 VueLoaderPlugin
],
optimization: {
minimizer: [
`...`, // 使用默认的 JavaScript 压缩工具
new CssMinimizerPlugin({
filename: '[name].[contenthash].css',
}), // 添加 CSS 压缩
],
},
}
调试服务
调试服务需要用到 webpack devServer,它会自动启动一个 http 服务,支持热更新,方便调试,详细配置见
// 配置开发服务器
devServer: {
client: {
overlay: false, // 禁用错误覆盖层,个人喜好这个可选,
},
static: {
directory: path.join(__dirname, '../dist'), // 静态文件目录
},
hot: true, // 启用热模块替换
open: true, // 启动后自动打开浏览器
historyApiFallback: true, // 支持前端路由
port: 8080
},
路径别名
添加路径别名,可以让代码少写一些 '../../' ,同时webpack也会缓存路径,增加效率
{
resolve: {
alias: {
'@': path.resolve(__dirname, '../src'),
},
extensions: ['.js', '.vue', '.json', '.ts', '.tsx'],
},
}
这里我们简单配置一个 @ 指向根目录就行
总结
思维导图
完整配置
dev
/* eslint-disable @typescript-eslint/no-require-imports */
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const webpack = require('webpack');
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
// 开发模式:对构建速度进行优化,自动生成 source-map
mode: 'development',
// 入口文件
entry: path.resolve(__dirname, '../src/main.ts'),
// 输出文件配置
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, '../dist'),
},
// 配置开发服务器
devServer: {
client: {
overlay: false, // 禁用错误覆盖层
},
static: {
directory: path.join(__dirname, '../dist'), // 静态文件目录
},
hot: true, // 启用热模块替换
open: true, // 启动后自动打开浏览器
historyApiFallback: true, // 支持前端路由
port: 8080,
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../src'),
},
extensions: ['.js', '.vue', '.json', '.ts', '.tsx'],
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.ts$/, // 添加 .ts 文件的处理规则
loader: 'ts-loader', // 使用 ts-loader 编译 TypeScript
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
transpileOnly: true, // 添加此行以提高编译速度
compilerOptions: {
// 添加编译器选项
moduleResolution: 'node',
},
},
},
{
test: /\.(js|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-typescript'],
plugins: ['@vue/babel-plugin-jsx'],
},
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'assets/[name].[hash][ext]',
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../index.html'),
inject: true,
}),
// process.env.ANALYZE &&
// new BundleAnalyzerPlugin({
// analyzerPort: process.env.ANALYZER_PORT || 8889,
// analyzerHost: 'localhost',
// openAnalyzer: true,
// }),
new VueLoaderPlugin(), // 必须添加 VueLoaderPlugin
],
// 配置 source-map,用于开发时调试
devtool: process.env.NODE_ENV === 'development' ? 'eval-source-map' : false,
};
prod
/* eslint-disable @typescript-eslint/no-require-imports */
const { merge } = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const common = require('./webpack.dev.config');
module.exports = merge(common, {
mode: 'production',
output: {
filename: 'bundle.[contenthash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
optimization: {
splitChunks: {
chunks: 'all',
},
},
});
原文地址:https://webfem.com/post/webpack-vue,转载请注明出处