16

It has been a long time since Webpack5 was officially released, and after a while, I found it really fragrant. The new features of webpack5 make our configuration more convenient than previous versions, and the build speed has also made a qualitative leap. This article focuses on explaining the questions encountered in the process of building vue3 + webpack 5 development environment from 0 to 1.

Project address: webpack5-vue3

Demo address: https://zhouyupeng.github.io/webpack5-vue3/#/

First look at the configured project directory structure

├─build
│  ├─webpack.base.conf.js 
│  ├─webpack.dev.conf.js   
│  ├─webpack.prod.conf.js 
│  ├─webpack.rules.conf.js 
├─node_modules
├─public
|  |-index.html
└─src
|  ├─api
|  ├─assets
|  ├─components
|  ├─filters
|  ├─plugins
|  ├─router
|  ├─store
|  ├─style
|  ├─utils
|  ├─views
|  |-App.vue
|  |-main.ts
|-.env.dev
|-.env.test
|-.env.prod
|-.gitigore
|-babel.config.js
|-package.json
|-postcss.config.js

Next, we use Webpack5 from 0 to build a complete Vue3 development environment!

Environment (environment)

webpack 5 runs on Node.js v10.13.0+ version.

This article refers to the dependent version number

├── webpack           5.43
├── webpack-cli       4.7.2
├── node              14.17.0

Initialize the directory

Step 1: Create a directory and initialize package.json

mkdir webpack5-vue3 && cd webpack5-vue3
yarn init -y

Step 2: Install the three-piece webpack

yarn add webpack webpack-cli webpack-dev-server -D

Notice:

  1. -D is equivalent to --save-dev; it depends on the development environment
  2. -S is equivalent to --save; it depends on the production environment

Step 3: Initialize directories and files

  • Create the ./build/webpack.config.js file and ./src/main.js file and write the webpack package configuration code

    // webpack.config.js
    const path = require('path');
    module.exports = {
      entry: path.resolve(__dirname, '../src/main.js'), // 入口
      output: {
          path: path.resolve(__dirname, '../dist'),
          filename: './js/[name].[chunkhash].js',
          publicPath: './',
      },
    }
  • Write the packaging command in the scripts of package.json

    "build": "webpack --config ./build/webpack.config.js --mode production --progress --color -w"

    Detailed parameters

  • --config or -c: Provide the path to the webpack configuration file, for example ./webpack.config.js
  • --mode: The configuration environment can also be written in the configuration file without configuring mode default production mode packaging
  • --progress: enable printing of compilation progress during the build process
  • --color: enable console color
  • --watch or -w: monitor file changes

Run the packaging script yarn build see that webpack is running and the packaging is successful.

Configure the development server

webpack5 + webpack-cli4 The command to start the development server has been changed from webpack-dev-server to webpack serve,

"build": "webpack serve --config ./build/webpack.config.js --mode development --progress --color",

Another problem occurred after running. Change the code console and recompile, but the hot update invalid.

Take a look at the comparison of network screenshots after invalid startup and valid startup:
gPONlR.png
gPxobq.png

I found a circle on the Internet and said that deleting the browserslist in package.json can be updated. As of the time I wrote this article, I installed the dependent version.
Finally, issues 1610169f7dcdb7. According to the official explanation, it seems that this problem will only be fixed in webpack-dev-server@4.X. Install the latest beta version yarn add webpack-dev-server@lastest -D . Run the code and find that the hot update is successful.
After installing webpack-dev-server version 4.X, the configuration has changed a lot, and many previous configurations have been discarded.
4.x configuration point, I click or see here

Package by environment

In our usual project development, there are generally: development environment, test environment, pre-release environment and production environment. Now let's split the environment of the webpack configuration file.

Split files
├─build
│  ├─webpack.base.conf.js   //公共配置
│  ├─webpack.dev.conf.js    //mode为development配置
│  ├─webpack.prod.conf.js   //mode为production配置
│  ├─webpack.rules.conf.js  //loader配置
Configure environment variables

Use dotenv to load different environment variables on demand. The environment variable VUE CLI3 is also used by this plugin

  • Install dotenv plugin

    yarn add dotenv -D
  • Modify webpack.base.conf.js

    //...
    const envMode = process.env.envMode
    require('dotenv').config({ path: `.env.${envMode}` })
    // 正则匹配以 VUE_APP_ 开头的 变量
    const prefixRE = /^VUE_APP_/
    let env = {}
    // 只有 NODE_ENV,BASE_URL 和以 VUE_APP_ 开头的变量将通过 webpack.DefinePlugin 静态地嵌入到客户端侧的代码中
    for (const key in process.env) {
      if (key == 'NODE_ENV' || key == 'BASE_URL' || prefixRE.test(key)) {
          env[key] = JSON.stringify(process.env[key])
      }
    }
    
    plugins: [
      //...
      new webpack.DefinePlugin({ // 定义环境变量
          'process.env': {
              ...env
          }
      })
    ]
    
  • Modify package.json

    "scripts": {
    "dev": "cross-env envMode=dev webpack serve --config ./build/webpack.dev.conf.js  --color",
    "build": "cross-env envMode=prod webpack --config build/webpack.prod.conf.js  --color",
    "build:test": "cross-env envMode=test webpack --config build/webpack.prod.conf.js  --color"
    },
  • Configuration variable file
.env.dev
.env.test
.env.prod

After the configuration is complete, you can use environment variables like VUE CLI3 point I click me

Configure core functions

Convert ES6+ to ES5

Because some browsers cannot parse ES6+ and other advanced grammars, they need to be converted into lower version grammars that the browser can parse

yarn add @babel/core @babel/preset-env babel-loader -D
yarn add core-js -S

loader configuration

// webpack.rules.conf.js
rules: [
    {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
            loader: 'babel-loader',
        }
    }, 
]

Babel configuration file
Babel's configuration file is the file that Babel will look for in the current directory by default when it is executed. There are mainly .babelrc, .babelrc.js, babel.config.js and package.json. Their configuration items are the same, and their functions are the same. You only need to choose one of them.
It is recommended to use the suffix name js configuration file, because js can be used to do some logical processing, which is more applicable.

// babel.config.js
const presets = [
    ["@babel/preset-env", {
        "useBuiltIns": 'usage', // 这里配置usage 会自动根据你使用的方法以及你配置的浏览器支持版本引入对于的方法。
        "corejs": "3.11.0" // 指定 corejs 版本 
    }]
]
const plugins = [
]
module.exports = {
    plugins,
    presets

}
Generate HTML

Install the html-webpack-plugin plug-in to process the index.html file. The function of this plug-in is to automatically generate the correct project entry file according to the provided template file, and automatically insert the webpack packaged js file into it

yarn add html-webpack-plugin -D

plugins configuration

webpack.base.conf.js
new HtmlWebpackPlugin({
    template: path.resolve(__dirname, '../public/index.html'),
    filename: 'index.html',
    title: 'webpack5+vue3',
    minify: {
        html5: true, // 根据HTML5规范解析输入
        collapseWhitespace: true, // 折叠空白区域
        preserveLineBreaks: false,
        minifyCSS: true, // 压缩文内css
        minifyJS: true, // 压缩文内js
        removeComments: false // 移除注释
    },
    files: prodMode ? cdn.prod : cdn.dev //CDN引入文件配置
}),

The index.html source file here is placed in the ../public/ folder.
Note: configuring dynamic web title for <title> , you need to change the content <%= htmlWebpackPlugin.options.title %>
CDN introduces js

<% for (var i in
htmlWebpackPlugin.options.files&&htmlWebpackPlugin.options.files.js) { %>
<script src="<%= htmlWebpackPlugin.options.files.js[i] %>"></script>
<% } %>
Add css and sass support
yarn add style-loader css-loader -D
yarn add node-sass sass-loader -D
yarn add autoprefixer postcss-loader -D 

loader configuration

//webpack.rules.conf.js
{
    test: /\.(css|scss|sass)$/,
    use: [
        'style-loader',
        'css-loader',
        'postcss-loader',
        'sass-loader'
    ]
}

loader evaluate/execute from right to left (or bottom to top). In the above example, execution starts from sass-loader and ends with style-loader.

Configure alias alias

Create an alias of import or require to make it easier to import modules

// webpack.base.conf.js
resolve: {
    alias: {
        "@": path.resolve(__dirname, "../src"),
        assets: path.resolve(__dirname, '../src/assets/'),
        img: path.resolve(__dirname, '../src/assets/img'),
        utils: path.resolve(__dirname, '../src/utils'),
        api: path.resolve(__dirname, '../src/api'),
    },
},
Processing static resources such as pictures

Before Webpack5, we processed static resources such as PNG images, SVG icons, etc., which required url-loader, file-loader, and raw-loader. Webpack5 provides built-in static resource construction capabilities, we don't need to install additional loaders, only simple configuration can realize the packaging and sub-directory storage of static resources. These three loaders have also stopped updating on github.

webpack5 uses four new resource modules ( Asset Modules ) to replace these loader functions.

asset/resource divides the resource into separate files and exports the url, which is the function of the previous file-loader.
asset/inline exports resources in the form of dataURL (url(data:)), the function of the previous url-loader.
asset/source Export resources as source code. The previous raw-loader function.
The asset is automatically exported as a separate file or as a dataURL (8KB by default). Previously, there was a url-loader setting asset size limit.

//webpack.rules.conf.js
{
    test: /\.(png|jpg|svg|gif)$/,
    type: 'asset/resource',
    generator: {
        // [ext]前面自带"."
        filename: 'assets/[hash:8].[name][ext]',
    },
}

More configuration points, I click me

Clear the last build dist directory when packaging

The webpack version below 5.20 generally uses the plug-in clean-webpack-plugin to clear the content of the dist file. After version 5.20, the new output feature clean used to clear the dist file

//webpack.prod.conf.js
module.exports = {
  //...
  output: {
    clean: true, // Clean the output directory before emit.
  },
};

more configuration, click me

Output static resources to the root directory
yarn add copy-webpack-plugin -D

When some files do not need to be packaged by webpack and used directly, here we can use copy-webpack-plugin , when building, copy the static resources of public/ directly to the dist root directory

//webpack.prod.conf.js
new copyWebpackPlugin({
    patterns: [{
        from: path.resolve(__dirname, "../public"),
        to: './',
        globOptions: {
            dot: true,
            gitignore: true,
            ignore: ["**/index.html*"],
        }
    }]
}),
Extract style files

This plugin will extract CSS into a separate file, create a CSS file for each JS file that contains CSS, and support on-demand loading of CSS and SourceMaps.

yarn add mini-css-extract-plugin -D
//webpack.prod.conf.js
plugins: [
//...
    new miniCssExtractPlugin({
        filename: './css/[name].[contenthash].css',
        chunkFilename: './css/[id].[contenthash].css',
    })
],

Modify webpack.rules.conf.js

{
    test: /\.(css|scss|sass)$/,
    use: [
        !prodMode ? 'style-loader'
            : {
                loader: MiniCssExtractPlugin.loader,
                options: {
                    publicPath: '../',
                },
            },
        'css-loader',
        'postcss-loader',
        'sass-loader',
    ],
},

Identify .vue files

yarn add vue-loader@next @vue/compiler-sfc -D
yarn add vue@next -S

Note:

  • vue-loader: It is a loader plug-in based on webpack. It parses and converts .vue files, extracts the logic code script, style code style, and HTML template template. Vue 3.x needs to install vue-loader@next.
  • @vue/compiler-sfc: In the Vue 2.x era, the vue-template-compiler plug-in is required to process the .vue content as ast, and Vue 3.x becomes @vue/compiler-sfc.

modify webpack configuration

// webpack.rules.conf.js
rules: [
    {
        test: /\.vue$/,
        use: [
            'vue-loader'
        ]
    }
]

//webpack.base.conf.js
const { VueLoaderPlugin } = require('vue-loader/dist/index');
plugins: [
    new VueLoaderPlugin()
]

add App.vue

<template>
    <div>
        <p class="title">{{title}}</p>
    </div>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
    setup() {
        const title = ref('渐进式JavaScript 框架');

        return {
            title
        }
    }
})
</script>
<style scoped>
.title{
    color: #000;
}
</style>

modify

import { createApp } from 'vue' // Vue 3.x 引入 vue 的形式
import App from './App.vue' // 引入 APP 页面组建
 
const app = createApp(App) // 通过 createApp 初始化 app
app.mount('#root') // 将页面挂载到 root 节点

Run the code again and it runs successfully.

Install Vue Family Bucket

 yarn add vue-router@4 vuex@next axios -S

vw adaptation

yarn add postcss-loader postcss-px-to-viewport -D

Create a new postcss.config.js file

'postcss-px-to-viewport': {
    unitToConvert: 'px', // 需要转换的单位,默认为"px"
    viewportWidth: 750, //  设计稿的视口宽度
    unitPrecision: 5, // 单位转换后保留的精度
    propList: ['*'], // 能转化为vw的属性列表
    viewportUnit: 'vw', //  希望使用的视口单位
    fontViewportUnit: 'vw', // 字体使用的视口单位
    selectorBlackList: ['.ignore', '.hairlines', '.ig-'], // 需要忽略的CSS选择器
    minPixelValue: 1, // 最小的转换数值,如果为1的话,只有大于1的值会被转换
    mediaQuery: false, // 媒体查询里的单位是否需要转换单位
    replace: true, // 是否直接更换属性值,而不添加备用属性
    include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换,例如只转换 'src/mobile' 下的文件 (include: /\/src\/mobile\//)
    landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
    landscapeUnit: 'vw', // 横屏时使用的单位
    landscapeWidth: 568 // 横屏时使用的视口宽度
}

Remove the console.log of the production environment

Use TerserWebpackPlugin to remove console.log , compression JS, webpack5 comes after the latest terser-webpack-plugin , without having to re-install original point I point my

//webpack.prod.conf.js
minimizer: [
    new TerserPlugin({
        // 多进程
        parallel: true,
        //删除注释
        extractComments: false,
        terserOptions: {
            compress: { // 生产环境去除console
                drop_console: true,
                drop_debugger: true,
            },
        },
    })
],

Compile cache

Webpack5 has the built-in FileSystem Cache ability to accelerate the second build, which can be achieved through the following configuration

cache: {
    type: 'filesystem',
    // 可选配置
    buildDependencies: {
        config: [__filename],  // 当构建依赖的config文件(通过 require 依赖)内容发生变化时,缓存失效
    },
    name: '',  // 配置以name为隔离,创建不同的缓存文件,如生成PC或mobile不同的配置缓存
    ...,
},

After configuration, the second build speeds up quickly.
Precautions:

  • The attribute type of cache will be set to memory by default in development mode and disabled in production mode, so if you want to use cache in production packaging, you need to explicitly set it.
  • In order to prevent the cache from being too fixed and causing unawareness of changing the build configuration, the old cache is still used. By default, each modification of the build configuration file will cause the cache to restart. Of course, you can also actively set version to control the update of the cache.

Integrated Vant

yarn add vant@next -S
  • On-demand introduction

    yarn add babel-plugin-import -D
  • Change setting

    // babel.config.js
    const plugins = [
      ['import', {
          libraryName: 'vant',
          libraryDirectory: 'es',
          style: true
      }, 'vant']
    ]
  • vant adapts vw

Modify postcss.config.js

const path = require('path');
module.exports = ({file}) => {
    const designWidth = file.includes(path.join('node_modules', 'vant')) ? 375 : 750;
    return {
        plugins: {
            'postcss-px-to-viewport': {
                unitToConvert: 'px', // 需要转换的单位,默认为"px"
                viewportWidth: designWidth, //  设计稿的视口宽度
                unitPrecision: 5, // 单位转换后保留的精度
                propList: ['*'], // 能转化为vw的属性列表
                viewportUnit: 'vw', //  希望使用的视口单位
                fontViewportUnit: 'vw', // 字体使用的视口单位
                selectorBlackList: ['.ignore', '.hairlines', '.ig-'], // 需要忽略的CSS选择器
                minPixelValue: 1, // 最小的转换数值,如果为1的话,只有大于1的值会被转换
                mediaQuery: false, // 媒体查询里的单位是否需要转换单位
                replace: true, // 是否直接更换属性值,而不添加备用属性
                include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换,例如只转换 'src/mobile' 下的文件 (include: /\/src\/mobile\//)
                landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
                landscapeUnit: 'vw', // 横屏时使用的单位
                landscapeWidth: 568 // 横屏时使用的视口宽度
            }

        }
    }
}

Wepback's visual resource analysis plug-in

yarn add webpack-bundle-analyzer -D

Used to analyze which modules introduce which codes, and optimize the code purposefully
--analyze after the packaging script, such as yarn build --analyze , without additional configuration. The new version of webpack-cli has been supported. Original

at last

I don’t know if everyone has finished reading this article. If there are errors or inaccuracies in the article, you are welcome to point out and discuss them.

Welcome to follow

Welcome to follow the small program " advanced big front end", more than 800 front-end interview questions are viewed online


zhou_web
1.6k 声望1.1k 粉丝