webpack5 从零搭建 vue3 项目

news/2025/1/16 22:27:05/文章来源:https://www.cnblogs.com/limoonrise/p/18675858

目前 vue3 官网推荐的工具链已经是 vite 了,就算是要使用 webpack 甚至是 webpack5,也可以直接使用 vue-cli。然而之所以写这个,可以当是 webpack5 的一个学习文章。同时也是因为之前有个项目是在 vue3 刚出来的时候使用 vue-cli (那是官网还是推荐使用 webpack,以及但是得版本为 webpack4)开发的,手动改成 webpack5,想记录下。

Webpack

是什么

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

这个话是官网的原话,官网地址:webpack 中文

核心内容

  • Entry
  • Output
  • Loader

其作用是让 webpack 处理那些非 js, json 文件。由于 webpack 自身只能试别 js, json,其他后缀的文件需要经过 loader 处理,将他们转化成有效模块。loader 可以是同步的,也可以是异步的,支持链式调用。

  • Plugins

loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务:打包优化,资源管理,注入环境变量。plugin 会运行在 webpack 的不同阶段,贯穿整个编译周期,目的在于解决 loader 无法实现的其他事。

  • Module

vue3 项目搭建

首先创建项目名称,以及下载相关的库。

# 创建项目
mkdir webpack-vue3
cd webpack-vue3
# 初始化 npm
npm init -y
# 下载 webpack
npm install webpack webpack-cli webpack-dev-server -D
# 下载 vue
npm install vue
# 下载 css 相关 loader
npm install css-loader style-loader vue-loader postcss-loader postcss autoprefixer -D
# 下载 vue 相关
npm install vue-loader @vue/compiler-sfc -D
# 下载 babel 相关
npm install babel-loader @babel/core @babel/preset-env -D
# 下载 plugin
npm install html-webpack-plugin -D

首先根目录创建 srcpublic文件夹,文件夹内容如下所示:

<!-- public > index.html -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="app"></div>
</body>
</html>
// src > main.js
import { createApp } from 'vue'
import App from './App.vue'const app = createApp(App)
app.mount('#app')
<!-- src > App.vue -->
<template><div class="container"><p>Vue3 Project</p><p class="text">count: {{ count }}</p></div>
</template><script setup>
import { ref } from 'vue'
const count = ref(1)
</script><style>.text {color: blue;}
</style>

初始化 vue 单页面程序后,下面开始配置 webpack,在根目录下创建 webpack.config.js 文件。

// . > webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')module.exports = {mode: 'development',entry: './src/main.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist'),clean: true},devtool: 'source-map',devServer: {static: './dist',hot: true},module: {rules: [{test: /\.vue$/,use: 'vue-loader'},{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env']}}},{test: /\.css$/,use: ['style-loader', 'css-loader',{loader: 'postcss-loader',options: {postcssOptions: {plugins: [require('autoprefixer'), // 使用 autoprefixer 插件]}}}]},{test: /\.(png|jpg|gif|svg|jpeg)$/,type: 'asset/resource', 			// 使用 asset/resource 类型generator: {filename: 'public/images/[name].[contenthash:8][ext]', 	// 输出目录和文件名格式},}]},plugins: [new VueLoaderPlugin(),new HtmlWebpackPlugin({template: './public/index.html'})],resolve: {alias: {vue: 'vue/dist/vue.esm-bundler.js'},extensions: ['.js', '.vue', '.json']}
}

然后 package.json 配置脚本

"scripts": {"test": "echo \"Error: no test specified\" && exit 1","server": "webpack server","build": "webpack"},

完成到这一步,我们就可以在终端运行 npm run server 来跑起项目,也可以通过 npm run build 打包项目。这个只是一个简单的 webpack 配置,运行环境 mode 在正式打包的时候还要手动修改成 production,以及 source-map 移除等。对于要正式上线的项目,这样的配置往往是不够的。

优化 webpack 配置

拆分配置,配置运行环境

首先,我们先对项目进行环境的划分。

npm install cross-env -D

下载 cross-env 库,用于设置环境变量。下载完后,修改 package.json

{"scripts": {"test": "echo \"Error: no test specified\" && exit 1","server": "webpack server --config build/webpack.dev.js","build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js","build:test": "cross-env NODE_ENV=test webpack --config build/webpack.prod.js"},
}

--config 后面是指定的配置文件,这个我们待会创建。build 这个指令是用来打包正式上线的,build:test 这个是用来测试打包效果的,用来展示打包量化工具等。这个你也可以用来用作 测试服的打包。就比如有些公司会分内测,外测以及正式服。你就可以不写 build:test,直接用 innerouterformal 代替。

然后就是创建对应的配置文件了。根据上面的路径,在根目录创建 build 文件夹,里面创建 webpack.common.jswebpack.dev.jswebpack.prod.js 三个文件。

// build > webpack.common.jsconst path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')module.exports = {entry: path.resolve(__dirname, '../src/main.js'),output: {filename: 'public/js/bundle.js',path: path.resolve(__dirname, '../dist'),clean: true},module: {rules: [{test: /\.vue$/,use: 'vue-loader'},{test: /\.js$/,exclude: /node_modules/,use: 'babel-loader'},{test: /\.css$/,use: ['style-loader', 'css-loader', 'postcss-loader']},{test: /\.(png|jpg|gif|svg|jpeg)$/,type: 'asset/resource', 			// 使用 asset/resource 类型generator: {filename: 'public/images/[name].[contenthash:8][ext]', 	// 输出目录和文件名格式},}]},plugins: [new VueLoaderPlugin(),new HtmlWebpackPlugin({template: path.resolve(__dirname, '../public/index.html')}),],resolve: {alias: {'@': path.resolve(__dirname, '../src'),vue: 'vue/dist/vue.esm-bundler.js',},extensions: ['.js', '.vue', '.json']}
}

webpack.common.js 中的配置和 webpack.config.js 中的大体一致,移除了 devtooldevServer 的配置,其他的也只是写小修改,例如 output 的时候输出位置以及添加了@ 别名。babel-loaderpostcss-loader 的配置也提取出去了,这里要在根目录下创建 .babelrcpostcss.config.js

// . > babelrc
{"presets": ["@babel/preset-env"]
}
// . > postcss.config.js
module.exports = {plugins: [require('autoprefixer')]
}

接下来就是 webpack.dev.js

// build > webpack.dev.js
const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')module.exports = merge(commonConfig, {mode: 'development',devtool: 'source-map',devServer: {static: '../dist',hot: true,open: true},
})

dev 配置就是 devtool 以及 devServer 了,然后通过 webpack-mergecommondev 合并起来。

// build > webpack.prod.js
const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')module.exports = merge(commonConfig, {mode: 'production'
})

prod 当前来看则是这样,相对简单。

添加 sass 预处理器

npm install sass sass-loader -D

然后在 webpack.common.jsmodule.rules 中添加 scss 的规则

// build > webpack.common.js
moudle.exports = {// ...module: {rules: {//...{test: /\.scss$/,use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']}}}
}

然后 .vue 中就能使用 lang="scss" 以及引入 .scss 文件。

拆分 chunk

拆分之前,我们先安装一下 webpack-bundle-analyzer,它是一个用于分析 Webpack 打包结果的工具。它可以生成一个可视化的报告,帮助开发者理解各个模块的大小以及它们在最终打包文件中的占比。

npm i -D webpack-bundle-analyzer

然后我们在 webpack.prod.js 中配置一下,这里要用到我们前面做的环境区分。我们只在 build:test 的时候才使用 webpack-bundle-analyzer

// build > webpack.prod.js
const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')const ENV = process.env.NODE_ENV
console.log('运行环境:' + ENV)function getPlugins() {const plugins = []if (ENV === 'test') {plugins.push(new BundleAnalyzerPlugin({analyzerMode: 'static', // 生成静态报告openAnalyzer: true,}))}return plugins
}module.exports = merge(commonConfig, {mode: 'production',plugins: getPlugins()
})

这时候我们执行 npm run build:test 就可以看到打包出的 bundle.js 大小以及分布图。

接下来就是对 chunk 拆分了

通过 optimization.splitChunks 来进行拆分

// build > webpack.prod.js
module.exports = merge(commonConfig, {mode: 'production',plugins: getPlugins(),optimization: {splitChunks: {cacheGroups: {defaultVendors: {name: 'vendor',test: /[\\/]node_modules[\\/]/,priority: 1,chunks: 'all',minChunks: 1,minSize: 0},common: {name: 'common',minChunks: 2,priority: 0,chunks: 'all',reuseExistingChunk: true,minChunks: 2,minSize: 0}}}},
})

配置完这个后,如果你直接执行 build 测试的话,会报错。因为这里你 output 的配置中的 filename 是定死的文件名。这里需要修改一下 webpack.common.js 中的配置。

// build > webpack.common.js
module.exports = {entry: path.resolve(__dirname, '../src/main.js'),output: {// 修改部分filename: 'public/js/[name].[contenthash:8].js',path: path.resolve(__dirname, '../dist'),clean: true},// ... 其他配置
}

这时在进行 npm run build:test ,就可以发现会打包出两个 js 文件。同时可以看到解析图也发生了改变。

对于某个路由的拆分

路由的拆分比较简单,只需要动态引入组件的时候使用 webpackChunkName

首先实现路由环境。

npm i vue-router

然后在 src 下创建 routersviews 文件夹。一个用来存路由配置,一个用来存具体的路由组件。

// src > routers > index.js
import { createWebHashHistory, createRouter } from "vue-router"const Home = () => import(/* webpackChunkName: "home" */ '@/views/home/index.vue')
const Detail = () => import(/* webpackChunkName: "detail" */ '@/views/detail/index.vue')const routes = [{path: '/',component: Home},{path: '/detail',component: Detail}
]const router = createRouter({history: createWebHashHistory(),routes
})export default router// src > main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from "./routers"const app = createApp(App)
app.use(router).mount('#app')
<!-- src > views > detail > index.vue -->
<template><div class="detail-container">detail{{ count }}</div>
</template><script setup>
const count = ref(1)
</script><style lang="scss">
.detail-container {color: yellow;
}
</style><!-- src > views > home > index.vue -->
<template><div class="main-container">home{{ count }}</div>
</template><script setup>
const count = ref(1)
</script><style lang="scss">
.main-container {color: blue;
}
</style><!-- src > App.vue -->
<template><div class="container"><p>Vue3 Project</p><p class="text">count: {{ count }}</p><!-- 新增部分 --><RouterView></RouterView></div>
</template><script setup>
// 新增部分
import { RouterView } from 'vue-router'
import { ref } from 'vue'
const count = ref(1)
</script><style lang="scss">
.container {.text {color: blue;}
}
</style>

运行 build:test 会发现,这时候会多出 detail.[base:8]home.[base:8]。即说明拆分成功了。

提取 css

目前我们打包出来的都是 js 文件,样式也是在 js 文件中的。这里我们需要 mini-css-extract-plugin 库来将 css 样式从 javascrip 中提取出来。

npm install mini-css-extract-plugin -D

配置如下

// build > webpack.common.js
// ... 其他已有引用
const MiniCssExtractPlugin = require('mini-css-extract-plugin')module.exports = {module: {rules: [// ... 其他loader// 修改部分{test: /\.css$/,use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']},{test: /\.scss$/,use: [MiniCssExtractPlugin.loader,'css-loader','postcss-loader','sass-loader']},]},plugins: [// ... 其他 pluginsnew MiniCssExtractPlugin({filename: 'public/css/[name].[contenthash:8].css'}),]
}

配置完成后打包,就会生成对应的 css 文件。

添加缓存

webpack5 自己提供了 cache 功能

// build > webpack.prod.js
module.exports = {cache: {type: 'filesystem'}
}

打包后在 node_modules 中可以看到 .cache 文件夹。

其他配置

利用 progress-bar-webpack-plugin 库,显示打包进度。

// build > webpack.prod.js
// ... 其他引入
const ProgressBarPlugin = require('progress-bar-webpack-plugin')function getPlugins() {const plugins = [new ProgressBarPlugin({format: `  :msg [:bar] ${chalk.green.bold(":percent")} (:elapsed s)`})]if (ENV === 'test') {// ... test 配置}return plugins
}

同时可以关闭自带的显示信息

module.exports = {// ...stats: {// 显示详细信息all: false,assets: true, // 显示打包的文件timings: true, // 显示构建时间modules: false,chunks: false,version: true, // 显示 Webpack 版本errors: true, // 显示错误},
}

最终打包的时候可以看到具体进度以及耗时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/870327.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025-1-12至16-uniapp初体验

2025-1-12 今天主要就是在熟悉app开发软件应用,发现它的页面开发起来跟我们的web是一样的,初始界面就跟VScode操作一样,毕竟第一步是要做页面,然后它的控制台跟tomcat集成之后使用很像,之后就是复习一下web的css。盒子模型:margin:外边距 控制边框离屏幕的距离(top 上…

谷歌60s视频生成模型Veo的技术亮点

谷歌60s视频生成模型Veo的技术亮点如下: 高分辨率长视频生成 高分辨率输出:能够生成高质量的10谷歌60s视频生成模型Veo的技术亮点如下: 高分辨率长视频生成高分辨率输出:能够生成高质量的1080p分辨率视频,可满足长视频内容制作需求,如用于电影、广告等对画质要求较高的场…

【夸克网盘福利】如何领取1TB免费空间?小白三分钟学会!

Hello 大家好!我是你们的网盘省钱达人,今天给大家带来一个超实用的小技巧——**如何用夸克网盘免费领取1TB的存储空间**!没错,不用花一分钱,就能获得超大容量,随便存视频、照片、大文件,彻底告别“存储焦虑”。教程全程亲测有效,小白也能三分钟学会!废话不多说,快跟着…

Catlike Coding Custom SRP笔记 - SRP项目搭建

什么是SRP? 可编程渲染管线 (Scriptable Render Pipeline) 是 Unity 内置渲染管线的替代方案。 使用 SRP 可以通过 C# 脚本控制和定制渲染流程URP和SRP的区别? URP是基于SRP实现的一套渲染管线(由Unity官方实现,并以模板项目的方式提供给开发者使用)LWRP又是啥? 轻量级渲…

使用 Perspective 为 AI 艺术添加真实世界的深度

使用 Perspective 为 AI 艺术添加真实世界的深度 📖阅读时长:10分钟 🕙发布时间使用 Perspective 为 AI 艺术添加真实世界的深度 📖阅读时长:10分钟 🕙发布时间:2025-01-16近日热文:全网最全的神经网络数学原理(代码和公式)直观解释 欢迎关注知乎和公众号的专栏内…

字节跳动发布开源 Lip Sync AI 模型,视频换声对口型超轻松!

ByteDance新开源模型LatentSync,视频换声对口型超轻松! 阅读时长:9分钟 论文地址ByteDance新开源模型LatentSync,视频换声对口型超轻松!阅读时长:9分钟 论文地址: https://arxiv.org/pdf/2412.09262 发布时间:2025年1月8日字节跳动最近推出了LatentSync,这是一款全新的…

MobaXterm(远程终极工具箱) v24.4汉化专业版

MobaXterm是一款集多种远程功能于一身的工具,它通过支持SSH、Telnet、RDP、VNC等协议,让用户能够轻松远程连接至不同操作系统,如Linux、Unix和Windows。此外,它还具备文件传输功能,支持SCP、SFTP、FTP协议,方便用户在本地与远程设备间传输文件。关键特性图形界面支持:可…

https证书一键自动续期,帮你解放90天限制

前言 前几天网站证书到期,发觉证书颁发每次只能90天有效期,这谁能忍受,于是乎发觉网上有免费的一键续期脚本,真正解放我们的双手。项目如下acme.sh。 期间由于"墙"的原因,踩了很多的坑,此文记录一下踩坑的过程,同时也帮助我们"墙内"的程序员,不需要…

对rpc长连接与短连接的思考

RPC项目中长连接和短连接各有优劣,长连接适用于少量客户端,提高效率;短连接则更适合大量客户端,避免服务器过载。结合L4和L7负载均衡,合理选择连接方式,提升系统性能和稳定性。对rpc长连接与短连接的思考 对于rpc项目,在接受大佬指导的时候曾问过对于长连接和短连接是如…

【Windows攻防】通过代码研究空字节和无文件方式注册表隐藏技术

这篇文章收录于《取证实录》第四季中。 注册表隐藏技术通常用于恶意软件、后门程序或攻击者企图在系统中保持隐蔽,绕过安全检查和防御系统。 常见的隐藏技术有:使用非法字符隐藏注册表项(如PlugX、TDL4/Alureon(Rootkit))、利用默认键值(空字符串)隐藏(如Adwind RAT)…