Use webpack5 to manually build a vue development environment

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.jsonand 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.jsonwill 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:

  1. webpack.common.jspublic environment configuration
  2. webpack.dev.jsDevelopment environment configuration
  3. webpack.prod.jsProduction 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 srcfolder - store the business code, and create a new folder in it main.js.assets

assetsfontsCreate 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-pluginplugin 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.jsConfigure devServerproperties in :

const path = require('path')
...

const devConfig = {
    
    
  ...
  devServer: {
    
    
    static: path.resolve(__dirname, '../dist'),
    port: 3000,
    open: true,
    hot: true
  },
  output: {
    
    
    ...
  }
}

...

package.jsonConfigure 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.jsConfigure module.roulesthe 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

insert image description here

After transforming with babel

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-TS3fsheg-1686705628388) (C:\Users\liuqi\Documents\Study-code\assets\img\1686696819918. png)]

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.

  1. Installation dependencies:

    npm i mini-css-extract-plugin css-minimizer-webpack-plugin -D
    
    

    webpack plugin link:

    mini-css-extract-plugin

    css-minimizer-webpack-plugin

  2. 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:

  1. Install the view framework vue:npm i vue
  2. 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 srcthe 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 srcthe 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 srcthe directory, create routerand storedirectory respectively, and then create new index.jsfiles in turn. For specific usage methods, please refer to the official website of vue.

edit /router/index.jsfile:

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.jsbe configured in the development environment:

...

const devConfig = {
    
    
  ...
  devServer: {
    
    
    ...
    // 配置history路由模式
    historyApiFallback: true
  },
  ...
}

...

Edit /store/index.jsfile:

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.jsdirectly to the directory when packaging :publicdist

...
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
  }
}

.eslintconfigCreate a new and .eslintignorefile 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.jsconfigure 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

Guess you like

Origin blog.csdn.net/qq_44900902/article/details/131200687