如何使用 webpack 设置 vue 项目。
这是关于页面
这篇文章将逐步指导您如何使用 webpack 设置 vue.js。您需要在计算机上安装 Node,了解 Vue 的基本工作原理,当然还需要一个代码编辑器。
创建文件夹和包 json 文件
安装依赖项
文件/文件夹结构
配置 webpack 以使用 babel 加载器和 vue 加载器
编写脚本以启动服务器
加载器、插件和代码拆分
最终 webpack 配置和观察
创建文件夹和包 json 文件
在终端中,使用mkdir
命令创建项目文件夹,然后使用cd
命令切换到创建的文件夹。 在您创建的文件中,运行命令创建文件npm init –y
package.json
安装依赖项
现在我们有一个package.json
文件来跟踪我们的依赖项,我们可以继续安装它们。
- 依赖项:首先,我们安装 vue、vue-router 和 core-js 作为依赖项。运行
npm install vue vue-router core-js --save
此命令将安装这三个包作为依赖项。 - 开发依赖项:现在我们安装 webpack、webpack-cli、webpack-dev-server、babel-loader、@babel /core、@babel /preset-env、vue-loader 和 vue-template-compiler。运行
npm install webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env vue-loader vue-template-compiler -D
此命令会将所有这些包安装为开发依赖项。安装完成后,我们的 package.json 文件应该如下所示 ```
{
“name”:“vue-webpack-setup”,
“version”:“1.0.0”,
“description”:“”,
“main”:“index.js”,
“scripts”:{
“test”:“echo \”错误:未指定测试\“&& exit 1”
},
“keywords”:[],
“author”:“”,
“license”:“ISC”,
“dependencies”:{
“core-js”:“^3.6.5”,
“vue”:“^2.6.12”,
“vue-router”:“^3.4.3”
},
“devDependencies”:{
“ @babel /core”:“^7.11.6”,
“ @babel /preset-env”:“^7.11.5”,
“babel-loader”:“^8.1.0”,
“vue-loader”:“^15.9.3”,
“vue-template-compiler”:“^2.6.12”,
“webpack”:“^4.44.1”,
“webpack-cli”:“^3.3.12”,
“webpack-dev-server”:“^3.11.0”
},
}
## File/Folder structure <a name="p-3"></a>
Our folder structure would be similar to the default folder structure we get when using the vue cli to create a project. So lets create a public folder and an src folder in the root of our project. In the public folder, add a **favicon.ico** file and create an **index.html** file. In the **index.html** file, add this boilerplate
<!DOCTYPE html>
Vue app
<!-- 构建的文件将被自动注入 -->
In our src folder lets create an **App.vue** file and a **main.js** file.
N.B: **App.vue** file starts with a capital letter.
In our **App.vue** file, add this code
首页| >关于我们>
//@import url(" https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" );
// :root {
// --font: Roboto, sans-serif;
// --textColor: #374961;
// --linkActiveColor: #41b783;
// }
// #app {
// font-family: var(--font);
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// text-align: center;
// color: var(--textColor);
// .logo {
// 宽度:20%;
// }
// }
// .nav {
// 填充:30px 0 100px 0;
// a {
// 字体粗细:500;
// 颜色:var(--textColor);
// 边距:0 5px;
// }
// a.router-link-exact-active {
// 颜色:var(--linkActiveColor);
// }
// }
the scss style is commented out because we don't have a loader to process **.scss** files yet.
In our **main.js** file, add this code
从“vue”导入Vue;
从“。/App.vue”导入App;
从“。/router”导入路由器;
新的 Vue({
路由器,
渲染:(h)=> h(App),
})。$mount(“#app”);
Now we create three folders in our src folder namely, assets, router, views. In the assets folder, lets add an image and call it **logo.png**. In the router folder, create an **index.js** file and add this code in the **index.js** file
从“vue”导入 Vue;
从“vue-router”导入 VueRouter;
从“../views/Home.vue”导入 Home;
Vue.使用(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/about",
name: "About",
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
];
const router = new VueRouter({
模式:“history”,
路由,
});
导出默认路由器;
notice how we imported the about component in the router, this kind of import tells webpack to lazyload the about component.
In our views folder, lets create a file called **Home.vue**.
N.B: File names should start with capital letter.
Now, let's add this code in our **Home.vue** file
<h1>👋Hello world🌎</h1>
the image is commented out because we don't have a loader to process such file yet.
then add this to our **About.vue** file
这是关于页面
If done correctly, we should have a folder structure that looks like this

## Configure webpack to use babel loader and vue loader <a name="p-4"></a>
Babel loader helps transpile ECMAScript 2015+ code into JavaScript that can be run by older JavaScript engines. While vue loader helps transform vue components into plain JavaScript module.
To configure webpack to use these loaders, we need to create two files namely, **babel.config.js**, and **webpack.config.js**.
In the **babel.config.js** file lets add this code
module.exports = {
预设:[
[
“ @babel /preset-env”,
{
useBuiltIns:“usage”,
corejs:3,
},
],
],
};
@babel/preset-env helps to detect browsers we want to support so babel loader knows how to go about transpiling our JavaScript code. we would need to add a browserslist option in our **package.json** file so babel knows what browsers we want to support. So in our **package.json** file, let's add
"browserslist": [
"> 1%",
"最后 2 个版本",
"未死"
]
Ideally you would want to compile as little code as possible, so support only relevant browsers. The useBuiltIns and corejs options are for polyfill imports, you can read more about it [here](https://babeljs.io/blog/2019/03/19/7.4.0).
In our **webpack.config.js** file lets add this code
const { VueLoaderPlugin } = require("vue-loader");
const path = require("path");
module.exports = {
入口:{
main:"。/src/main.js",
},
输出:{
path:path.resolve(__dirname,“dist”),
},
模块:{
规则:[
{
测试:/.js$/,
排除:/node_modules/,
使用:{
加载器:"babel-loader",
},
},
{
测试:/.vue$/,
加载器:"vue-loader",
},
],
},
插件:[
new VueLoaderPlugin(),
],
解析:{
别名:{
vue$:"vue/dist/vue.runtime.esm.js",
},
扩展:["*", ".js", ".vue", ".json"],
},
};
From the code above we import VueLoaderPlugin from vue-loader and the path module which we will be using to configure our entry and output point so webpack will know where to start compiling from and where to put our compiled code after compiling. You can read more about VueLoaderPlugin [here](https://vue-loader.vuejs.org/guide/#vue-cli).
In the code above we see a module option where we define some rules, the first rule tells webpack to use babel loader to transpile all files having a **.js** extension excluding everything in the node_modules folder, while the second rule tells webpack to apply the vue loader to any file with a **.vue** extension.
The resolve option in the code above has an alias and extension key value pair, alias has a value which defines a vue alias and helps us import vue packages without using relative path, while extension has a value which tells webpack how to resolve imports and enables us import files without the extension, you can read more about it [here](https://webpack.js.org/configuration/resolve/#resolveextensions).
## Write scripts to start your server <a name="p-5"></a>
To see our setup work, we’ll need to write scripts in our **package.json** file to run the webpack-dev-server. So go into the **package.json** file and add these to the scripts object.
“build”:“webpack --mode production”,
“start”:“webpack-dev-server --mode development”
Now we can go back to our terminal and run `npm run start` to start up webpack development server, our project should compile successfully else you can go through the steps again or drop a comment, I’ll be glad to help you out.
N.B: We won't be able to view our project in the browser yet because we haven't configured the htmlWebpackPlugin and webpack doesn't know where to insert our bundle files.
## Loaders, Plugins, and Code Splitting <a name="p-6"></a>
Loaders and plugins are third-party extensions used in handling files with various extensions. Just like we used vue-loader to handling files with **.vue** extension, we have loaders and plugins for **.scss** files, **.html** files, images, etc.
Basically when you import/require files or modules, webpack tests the path against all loaders and passes the file to whichever loader passes the test. you can read more about loaders [here](https://webpack.docschina.org/loaders/)
In this post, we will make use of file-loader, sass-loader, css-loader, style-loader, CleanWebpackPlugin, MiniCssExtractPlugin, htmlWebpackPlugin, autoprefixer. To install these loaders and plugin, we run `npm install file-loader sass sass-loader css-loader style-loader postcss postcss-loader autoprefixer clean-webpack-plugin html-webpack-plugin mini-css-extract-plugin -D`
* file-loader: The file-loader is used to process files like images, videos, fonts. To use file-loader, insert this code into **webpack.config.js** file
{
test: /\.(eot|ttf|woff|woff2)(\?\S*)?$/,
loader: "file-loader",
options: {
name: "[name][contenthash:8].[ext]",
},
},
{
test: /\.(png|jpe?g|gif|webm|mp4|svg)$/,
loader: "file-loader",
options: {
outputPath: "assets",
esModule: false,
},
},
* working with **.css** and **.scss** files: For webpack to correctly process **.css** and **.scss** files, the order in which you arrange loaders is important. first we need to import MiniCssExtractPlugin and autoprefixer in our **webpack.config.js** file like this
`const MiniCssExtractPlugin = require("mini-css-extract-plugin");`
`const autoprefixer = require("autoprefixer");`
then we add this code to the module of our **webpack.config.js** file
{
test: /\.s?css$/,
use: [
"style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
plugins: () => [autoprefixer()],
},
},
"sass-loader",
],
},
we also need to enable the MiniCssExtractPlugin in the plugin section of our **webpack.config.js** file like this.
new MiniCssExtractPlugin(),
sass-loader: The sass-loader is first used to process all **.scss** files and compiles them to **.css** files.
postcss-loader: After sass-loader is done converting **.scss** files to **.css** files, postcss-loader and autoprefixer is then used to process the **.css** files and add vendor prefix to the css postcss.
css-loader: The css-loader then helps to return the css in **.css** files that are imported or required in the project.
style-loader: style-loader takes the css returned by css-loader and inserts it into the page.
MiniCssExtractPlugin: The MiniCssExtractPlugin helps create a separate css file from **.css** file imports, it is helpful for code splitting.
* htmlWebpackPlugin: this plugin helps to automatically generate an **index.html** file and inserts our JavaScript bundle into the html body. To use the htmlWebpackPlugin, we first import it into our **webpack.config.js** file like this
`const htmlWebpackPlugin = require("html-webpack-plugin");`
then enable the plugin in the plugin section by adding this code
new htmlWebpackPlugin({
template: path.resolve(__dirname, "public", "index.html"),
favicon: "./public/favicon.ico",
}),
* CleanWebpackPlugin: This plugin helps to erase outdated bundle files so it can be replace with the recent file while building. To use this plugin we first import it into our **webpack.config.js** file like this
`const { CleanWebpackPlugin } = require("clean-webpack-plugin");`
then enable the plugin in the plugin section by adding this code
新的 CleanWebpackPlugin(),
Now we can uncomment the image tag in the **Home.vue** file and also the scss style in the **App.vue** file, start our development server and view our project in the browser.

The image above shows our bundle size when we build our project, presently our bundles does not have a random hash which helps with browser cache and we also need to split our code further by creating a vendor chunk and a runtime chunk.
To hash our css bundles, we pass an object
`{
filename: "[name].[contenthash:8].css",
chunkFilename: "[name].[contenthash:8].css",
}`
as params to the MiniCssExtractPlugin.
To hash our files we need to add
`name: "[name][contenthash:8].[ext]",`
to the options object of our file loader.
To hash our bundles we need to add
`filename: "[name].[contenthash:8].js",`
`chunkFilename: "[name].[contenthash:8].js",`
in our webpack output section.
If we build our project now, our bundles would have a random hash.

* Code Splitting is an optimization technique used in reducing bundle size into smaller chunks, which helps to reduce the load time of our app. To configure webpack to split our bundle into chunks, we need to add an optimization section to our **webpack.config.js** file.
优化:{
moduleIds:“hashed”,
runtimeChunk:“single”,
splitChunks:{
cacheGroups:{
vendor:{
test:/[\/]node_modules[\/]/,
name:“vendors”,
priority:-10,
chunks:“all”,
},
},
},
}
The code above tells webpack to create a runtime chunk, vendor chunk from our node_modules folder, and hash them. Now we should see a runtime bundle and a vendor bundle when we build the project again.

## Final webpack configuration and Observation <a name="p-7"></a>
Our final **webpack.config.js** file should look like this
const { VueLoaderPlugin } = require("vue-loader");
const htmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const autoprefixer = require("autoprefixer");
const path = require("path");
module.exports = {
条目:{
主要: “。/src/main.js”,
},
输出:{
文件名: “[name].[contenthash:8].js”,
路径: path.resolve(dirname, “dist”),
chunkFilename: “[name].[contenthash:8].js”,
},
模块:{
规则:[
{
测试:/.js$/,
排除:/node_modules/,
使用:{
加载器: “babel-loader”,
}, }, { 测试:/.vue$/, 加载器: “vue-loader ”, }
,
{
测试:/ . (eot|ttf|woff|woff2)(\?\S* )?$/, 加载器: “file-loader”, 选项:{ 名称 : “[name][contenthash:8].[ext]”, }, }, { 测试:/.(png|jpe?g|gif|webm|mp4|svg)$/, 加载器: “file-loader”, 选项:{ 名称:“[name][contenthash:8].[ext]”, outputPath:“assets/img”, esModule:false, }, }, { 测试:/.s?css$/, 使用:[ “style-loader”, MiniCssExtractPlugin.loader, “css-loader”, { 加载器:“postcss-loader”, 选项:{ 插件:()=> [autoprefixer()], }, }, “sass-loader”, ], }, ], }, 插件:[ new VueLoaderPlugin(), new CleanWebpackPlugin(), new MiniCssExtractPlugin({ 文件名:“[name].[contenthash:8].css”, chunkFilename:“[name].[contenthash:8].css”, }), new htmlWebpackPlugin({ 模板:path.resolve(
dirname,“public”, “index.html”),
favicon:“./public/favicon.ico”,
}),
],
resolve: {
alias: {
vue$: "vue/dist/vue.runtime.esm.js",
},
extensions: ["*", ".js", ".vue", ".json"],
},
优化: {
moduleIds: "hashed",
RuntimeChunk: "single",
splitChunks: {
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: "vendors",
优先级:-10,
块:“全部”,
},
},
},
},
devServer:{
historyApiFallback:true,
},
};
You can checkout the repo [here](https://github.com/lavikara/basic-vue-boilerplate)
* Observation: After I was done with the setup, I created a fresh vue3 project using the vue-cli and compared the bundle size of the vue3 project with the one I just set up and realised there wasn't a significant difference in the bundle size of both project.
This goes to show that there's really no point going through the stress of setting up your webpack. Except you absolutely need to change something, just use the vue-cli.
I should also add that setting up webpack yourself is not a bad idea because in the end, no knowledge is lost.👌
鏂囩珷鏉ユ簮锛�https://dev.to/lavikara/setup-vue-webpack-and-babel-boo