Use webpack5 to build a vue development environment
foreword
When we usually develop a vue project, we usually directly execute the following command to create a project according to the recommendation of the vue official website :
npm init vue@latest
This command will install and execute create-vue, which is Vue's official project scaffolding tool.
However, this is not the subject of this article. This article will record the process of using Webpack 5.0 to configure the Vue development environment, and learn more about what Vue CLI does in the process of creating a project.
Prepare
Introduction to the concept of webpack
If you have used webpack4 to configure the vue development environment before, you can see the migration from webpack4 to webpack5
Environment configuration
Initialize the project
Create a new project root directory folder, and name the folder as the project name. Enter the folder and execute the following command:
npm init -y
A file will be generated in the root directory package.json
and modified as follows:
{
"name": "webpack5-vue-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
},
"keywords": [],
"author": "ricky",
"license": "ISC"
}
Install webpack
Excuting an order:
npm i webpack webpack-cli -D
package.json
will appear in:
{
"name": "webpack5-vue-template",
...
"devDependencies": {
"webpack": "^5.86.0",
"webpack-cli": "^5.1.4"
}
}
Configure the packaging environment
Create a new directory under the project root path build
, and create three new files in it js
:
webpack.common.js
public environment configurationwebpack.dev.js
Development environment configurationwebpack.prod.js
Production environment configuration
Modify the scripts parameter of package.json, and pass in environment variables for judgment in the script when running the script:
{
...
"scripts": {
"build:dev": "webpack --progress --config ./build/webpack.dev.js",
"build": "webpack --progress --node-env production --config ./build/webpack.prod.js"
},
...
}
Under the root directory, create a new src
folder - store the business code, and create a new folder in it main.js
.assets
assets
fonts
Create a new and directory inside the directory img
.
Install webpack-merge
Install this dependency for merging common configuration with environment-specific configuration. Finally export the expected configuration file
npm i webpack-merge -D
webpack.common.js
const path = require('path');
module.exports = {
entry: {
main: path.resolve(__dirname, '../src/main.js')
},
output: {
path: path.resolve(__dirname, '../dist')
},
}
Configure resolve: omit some frequently used file paths
...
module.exports = {
entry: {
...
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../src'),
'@img': path.resolve(__dirname, '../src/assets/img')
},
extensions: ['.js', '.vue']
},
...
}
webpack.dev.js
const {
merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')
const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development'
const devConfig = {
mode,
output: {
filename: 'js/[name].js',
chunkFilename: 'js/[name].chunk.js'
}
}
module.exports = merge(commonConfig, devConfig)
webpack.prod.js
const {
merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')
const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development'
const prodConfig = {
mode,
output: {
filename: 'js/[name].[contenthash:8].js',
chunkFilename: 'js/[name].[contenthash:8].chunk.js'
}
}
module.exports = merge(commonConfig, prodConfig)
Generate index.html in the dist directory
Create a new one in the root directory /public/index.html
:index.html
<!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">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>
Install html-webpack-plugin
plugin dependencies:
npm i html-webpack-plugin -D
Configure the html template in webpack.common.js
:
...
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'),
title: 'This is a template'
})
],
output: {
...
}
}
Configure the development environment
DevServer hot update
Install server dependencies, execute the command:
npm i webpack-dev-server -D
webpack.dev.js
Configure devServer
properties in :
const path = require('path')
...
const devConfig = {
...
devServer: {
static: path.resolve(__dirname, '../dist'),
port: 3000,
open: true,
hot: true
},
output: {
...
}
}
...
package.json
Configure the execution command of the attribute in script
:
{
...
"scripts": {
"serve": "webpack-dev-server --progress --config ./build/webpack.dev.js",
...
},
...
}
Babel language conversion
Install development dependencies:
npm i babel-loader @babel/core @babel/preset-env -D
Install production dependencies:
npm i @babel/polyfill core-js
webpack.common.js
Configure module.roules
the loading rules for js files in the public configuration :
...
module.exports = {
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
plugins: [
...
],
...
}
Create a new file in the project root directory babel.config.js
:
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: 3
}
]
]
}
Before using babel
After transforming with babel
css and stylus style packaging
Can also be scss or less, this example uses stylus. Install dependencies first:
npm i css-loader style-loader postcss-loader autoprefixer stylus stylus-loader -D
The css style conversion is converted when packaging, so the installation is a development dependency. Configure in webpack.dev.js
:
...
const devConfig = {
...
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
'postcss-loader'
]
},
{
test: /\.styl(us)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//启用/禁用或者设置在 css-loader 前应用的 loader 数量
importLoaders: 2
}
},
'postcss-loader',
'stylus-loader'
]
}
]
},
output: {
...
}
}
...
It is used here postcss
, so create a new configuration file in the root directory postcss.config.js
:
module.exports = {
plugins: [
require('autoprefixer') // 属性根据浏览器不同,自动添加样式前缀
]
}
Create a new one under the root directory .browserslistrc
:
> 1%
last 2 versions
not dead
not ie 11
Optimization: In the production environment, it is extracted into a separate css style file, and the style code is compressed. A development environment is not required.
-
Installation dependencies:
npm i mini-css-extract-plugin css-minimizer-webpack-plugin -D
webpack plugin link:
-
Configuration
webpack.prod.js
:... const MiniCssExtractPlugin = require('mini-css-extract-plugin') const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') ... const prodConfig = { ... module: { rules: [ { test: /\.css$/, use: [ // 压缩css文件,需配置的loader MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader' ] }, { test: /\.styl(us)$/, use: [ // 压缩css文件,需配置的loader MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 2 } }, 'postcss-loader', 'stylus-loader' ] } ] }, optimization: { minimizer: [ // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释 // `...`, new CssMinimizerPlugin(), // 这将仅在生产环境开启 CSS 优化。 // 如果还想在开发环境下启用 CSS 优化,请将 optimization.minimize 设置为 true: ] }, plugins: [ new MiniCssExtractPlugin({ // 决定输出的每个 CSS 文件的名称 filename: 'css/[name].[contenthash:8].css', // 决定非入口的 chunk 文件名称,仅在 webpack@5 下可用 chunkFilename: 'css/[name].[contenthash:8].chunk.css' }) ], output: { ... } } ...
Packaging of static resources such as fonts, pictures, and media
Configuration webpack.common.js
:
...
const isProduction = process.env.NODE_ENV === 'production'
module.exports = {
...
module: {
rules: [
...
{
test: /\.(ttf|woff|woff2|eto|svg)$/,
exclude: path.resolve(__dirname, '../src/assets/img'),
type: 'asset',
parser: {
dataUrlCondition: {
//如果一个模块源码大小小于 maxSize,那么模块会被作为一个 Base64 编码的字符串注入到包中, 否则模块文件会被生成到输出的目标目录中。
maxSize: 4 * 1024 // 4kb
}
},
generator: {
filename: isProduction
? 'static/fonts/[name].[contenthash:8][ext]'
: 'static/fonts/[name][ext]'
}
},
{
test: /\.(jpe?g|png|gif|svg)$/,
exclude: path.resolve(__dirname, '../src/assets/fonts'),
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
},
generator: {
filename: isProduction ?
'static/img/[name].[contenthash:8][ext]' :
'static/img/[name][ext]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)$/,
type: 'asset/resource',
generator: {
filename: isProduction ?
'static/video/[name].[contenthash:8][ext]' :
'static/video/[name][ext]'
}
}
]
},
...
}
For the description of rules.Rule.type, that is, the resource module, see the official website description for details
Configuration of packaging vue single file
Installation dependencies:
- Install the view framework vue:
npm i vue
- Install loader, compiler:
npm i vue-loader @vue/compiler-sfc -D
Configuration webpack.common.js
:
...
const {
VueLoaderPlugin } = require('vue-loader')
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.vue$/,
loader: 'vue-loader'
},
...
]
},
plugins: [
...
new VueLoaderPlugin()
],
...
}
So far, the vue development environment has been built!
Integrate Vue ecosystem function
app entry
In src
the directory, create a new App.vue
:
<template>
<div class="app">{
{ msg }}</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
msg: 'Hello world'
}
}
}
</script>
<style lang="stylus" scoped>
.app
color: skyblue
</style>
In src
the directory, create a new main.js
:
import {
createApp } from 'vue'
import App from './App'
const app = createApp(App)
app.mount('#app')
Add Vue Router and Vuex
Install production dependencies:
npm i vue-router vuex
Under src
the directory, create router
and store
directory respectively, and then create new index.js
files in turn. For specific usage methods, please refer to the official website of vue.
edit /router/index.js
file:
import {
createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// 懒加载。webpackChunkName 指定chunkname为 about
component: () => import(/* webpackChunkName: "about" */ '@/views/About')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
Note: The routing mode of is used here history
, so it needs to webpack.dev.js
be configured in the development environment:
...
const devConfig = {
...
devServer: {
...
// 配置history路由模式
historyApiFallback: true
},
...
}
...
Edit /store/index.js
file:
import {
createStore } from 'vuex'
const store = createStore({
state: {
count: 1
},
actions: {
add ({
commit }) {
commit('add')
}
},
mutations: {
add (state) {
state.count++
}
},
getters: {
getCount (state) {
return state.count
}
}
})
export default store
Add router and store to main.js:
import {
createApp } from 'vue'
import App from './App'
import router from './router'
import store from './store'
const app = createApp(App)
app.use(router).use(store).mount('#app')
Replace vuex with pinia hyperlink in Vue3
Define environment variables
Two variables need to be set in the vue3.x project for better tree-shaking
Revisewebpack.common.js
...
const webpack = require('webpack')
...
module.exports = {
...
plugins: [
...
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false
})
],
...
}
Configure packaging specifications
Copy public files when packaging
Installation dependencies:
npm i copy-webpack-plugin -D
Configuration , copy the following files webpack.common.js
directly to the directory when packaging :public
dist
...
const CopyPlugin = require('copy-webpack-plugin')
...
module.exports = {
...
plugins: [
...
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist'),
filter: (resourcePath) => {
if (resourcePath.includes('/public/index.html')) {
return false
}
return true
}
}
]
})
],
...
}
ESLint code specification
Installation dependencies:
npm i eslint eslint-webpack-plugin @babel/eslint-parser -D
npm i eslint-config-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-n -D
npm i eslint-plugin-vue -D
Execute eslint:
npx eslint --init
After executing the command, select the configuration item according to the prompt. Then a configuration file will be generated in the root directory of the project .eslintrc.js
, modify the file:
module.exports = {
root: true,
env: {
browser: true,
es2021: true
},
extends: [
'plugin:vue/vue3-essential',
'standard'
],
parserOptions: {
parser: '@babel/eslint-parser'
},
plugins: [
'vue'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 0
}
}
.eslintconfig
Create a new and .eslintignore
file in the root directory
-
.editorconfig
[*.{js,jsx,ts,tsx,vue}] indent_style = space indent_size = 2 trim_trailing_whitespace = true insert_final_newline = true
-
.eslintignore
/build/ /dist/
Configure eslint plugin in webpack
In webpack.common.js:
...
const ESLintPlugin = require('eslint-webpack-plugin')
...
module.exports = {
...
plugins: [
...
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx', 'vue']
})
],
...
}
Clear the last packaged content before packaging
Configuration webpack.common.js
:
...
module.exports = {
...
output: {
...
clean: true
}
}
SourceMap
This configuration is generally only required in the development environment, so webpack.dev.js
configure it in devtool
:
...
const devConfig = {
mode,
devtool: 'eval-cheap-module-source-map',
...
}
...
package analysis
Webpack packaging result analysis depends on installation:npm i webpack-bundle-analyzer -D
Configure directives in package.json
:
{
...
"scripts": {
...
"analyze": "webpack --progress --analyze --node-env production --config ./build/webpack.prod.js"
},
...
}
turn off some hints
When packaging in the production environment, there may be some performance prompts for large files, which can be turned off by configuration:
Modify webpack.prod.js
:
...
const prodConfig = {
...
performance: false,
output: {
...
}
}
...
some other configuration
When git submits, some files need to be ignored so that they will not be committed. Configuration: Create a new file in the following directory .gitignore
:
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
write at the end
The above operations are the whole process of building the Vue project environment with webpack5, and you are familiar with the configuration of webpack again during the actual operation.
References in this article:
Webpack 5.0 builds a Vue development environment from scratch
The process of creating a vue3 project by handwriting webpack