• 使用 Webpack 从 0 到 1 构建 Vue3 项目 + ts


    1.初始化项目结构

    原则:尽量跟vue-cli构建项目,尽量保持一致
    在这里插入图片描述
    创建 package.json

    npm init -y
    
    • 1

    创建 tsconfig.json

     tsc --init
    
    • 1

    如果没有 tsc,则执行下方命令

    npm install typescript -g
    
    • 1

    2.安装 webpack,补充智能提示

    安装 webpack

    yarn add webpack
    
    • 1

    安装完成后,如果 webpack 版本大于 3,则需要安装 webpack-cli

    yarn add webpack-cli 
    
    • 1

    安装启动服务

    yarn add webpack-dev-server
    
    • 1

    安装 html 模板

    yarn add html-webpack-plugin 
    
    • 1

    新建 webpack 配置文件 —— webpack.config.js
    使用 注解 帮我们增加智能提示

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {}
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.初步编写 webpack.config.js

    3.1设置入口文件及出口文件

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.2 指定 html 模板位置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
        ],
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4.配置 运行/打包 命令,首次打包项目

    在 package.json 中,配置下面两条命令:

        "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1",
            "dev": "webpack-dev-server",
            "build": "webpack"
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在 main.ts 中,随便写点内容,比如 const a = 1;并执行打包命令:

     npm run build
    
    • 1

    出现下方报错,告诉我们没指定 mode
    在这里插入图片描述
    去 webpack.config.js 中指定 mode —— 如果指定为 开发环境,那么打包出来的代码,不会被压缩

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
        ],
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    再执行一遍打包命令,顺利输出下方的文件,打包成功
    在这里插入图片描述

    5.添加 Vue 及相关配置

    5.1安装并引入 vue

    安装 vue

    yarn add vue
    
    • 1

    在 main.ts 中,引入 vue

    import { createApp } from 'vue'
    import App from './App.vue'
    // 注意:这里的 #app,需要在 public/index.html 中,写一个 id 为 app 的 div
    createApp(App).mount('#app')
    
    • 1
    • 2
    • 3
    • 4

    会发现各种爆红,因为 ts 此时还不认识 vue 呢,所以需要增加 vue 声明文件

    5.2 补充 vue 声明文件

    项目根目录下,新建 env.d.ts

    declare module "*.vue" {
       import { DefineComponent } from "vue"
       const component: DefineComponent<{}, {}, any>
       export default component
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样,main.ts 里就不会爆红了,因为 ts 现在认识 vue 了

    5.3 增加 vue 相关 webpack 配置,打包 vue 文件

    直接打包会报错,此时 webpack 不认识 template 之类的标签
    在这里插入图片描述
    需要安装 loader,协助 webpack 解析 vue 相关标签、文件

    yarn add vue-loader@next
    yarn add @vue/compiler-sfc
    
    • 1
    • 2

    在 webpack.config.js 中,补充配置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    const { VueLoaderPlugin } = require('vue-loader/dist/index')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, // 解析 .vue 结尾的文件
                    use: "vue-loader"
                },
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
            new VueLoaderPlugin(), // 解析 vue 模板
        ],
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    再打包一下,发现还是打包报错
    在这里插入图片描述
    因为此时 webpack 还不支持 typescript,可以把 lang=ts 先删除,就能成功打包了

    6.增加 删除上次打包文件 的配置

    随着打包次数的不断增多,打包文件也会越来越多
    在这里插入图片描述
    我们需要安装一个插件,在每次打包的时候,清空一下 dist 文件夹

    yarn add clean-webpack-plugin 
    
    • 1

    在 webpack.config.js 中,补充配置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    const { VueLoaderPlugin } = require('vue-loader/dist/index')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
     
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, // 解析 .vue 结尾的文件
                    use: "vue-loader"
                },
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
            new VueLoaderPlugin(), // 解析 vue 模板
            new CleanWebpackPlugin(), // 打包清空 dist
        ],
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    7.在 webpack 中,配置别名 @,替换 src

    在 resolve 中,进行配置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    const { VueLoaderPlugin } = require('vue-loader/dist/index')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, // 解析 .vue 结尾的文件
                    use: "vue-loader"
                },
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
            new VueLoaderPlugin(), // 解析 vue 模板
            new CleanWebpackPlugin(), // 打包清空 dist
        ],
        resolve: {
            alias: {
                "@": path.resolve(__dirname, './src') // 别名
            },
            extensions: ['.js', '.json', '.vue', '.ts', '.tsx'] // 识别后缀
        },
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    8.安装样式相关 loader,协助 webpack 解析样式

    新建 index.css,随便写点样式
    利用设置好的别名 @,在 main.ts 中进行引入,发现报错了
    在这里插入图片描述
    这个报错不是别名 @ 导致的,而是 webpack 不会处理 css 导致的

    需要安装一些 loader 协助 webpack 处理样式
    处理 css 文件

    yarn add css-loader
    
    • 1

    处理 style 样式

    yarn add style-loader 
    
    • 1

    处理 less 语法

    yarn add less
    yarn add less-loader 
    
    • 1
    • 2

    在 webpack.config.js 中,补充配置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    const { VueLoaderPlugin } = require('vue-loader/dist/index')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, // 解析 .vue 结尾的文件
                    use: "vue-loader"
                },
                {
                    test: /\.less$/, // 解析 less
                    use: ["style-loader", "css-loader", "less-loader"],
                },
                {
                    test: /\.css$/, // 解析 css
                    use: ["style-loader", "css-loader"],
                },
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
            new VueLoaderPlugin(), // 解析 vue 模板
            new CleanWebpackPlugin(), // 打包清空 dist
        ],
        resolve: {
            alias: {
                "@": path.resolve(__dirname, './src') // 别名
            },
            extensions: ['.js', '.json', '.vue', '.ts', '.tsx'] // 识别后缀
        },
    }
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    9.添加 TypeScript Loader,协助 webpack 处理 ts

    安装 typescript

    yarn add typescript
    
    • 1

    安装 typescript loader

    yarn add ts-loader
    
    • 1

    注意:ts loader 不能直接使用,他比别的 loader 多了 options(因为 ts loader 需要针对 vue 等单文件组件做单独处理)
    在 webpack.config.js 中,补充配置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    const { VueLoaderPlugin } = require('vue-loader/dist/index')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
     
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, // 解析 .vue 结尾的文件
                    use: "vue-loader"
                },
                {
                    test: /\.less$/, // 解析 less
                    use: ["style-loader", "css-loader", "less-loader"],
                },
                {
                    test: /\.css$/, // 解析 css
                    use: ["style-loader", "css-loader"],
                },
                {
                    test: /\.ts$/, // 解析 ts
                    loader: "ts-loader",
                    options: {
                        configFile: path.resolve(process.cwd(), 'tsconfig.json'),
                        appendTsSuffixTo: [/\.vue$/]
                    },
                }
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
            new VueLoaderPlugin(), // 解析 vue 模板
            new CleanWebpackPlugin(), // 打包清空 dist
        ],
        resolve: {
            alias: {
                "@": path.resolve(__dirname, './src') // 别名
            },
            extensions: ['.js', '.json', '.vue', '.ts', '.tsx'] // 识别后缀
        },
    }
     
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    每次改完配置文件,都需要重启,才能保证 webpack 配置生效

    10.美化 webpack 打包时的控制台输出

    11.externals 排除打包文件,使用 cdn 引入,实现性能优化

    上面的文件直接打包后,产生的文件高达 800k+
    在这里插入图片描述
    可以考虑不打包 vue,在 public/index.html 中,采用 cdn 方式引入 vue,进而减小体积
    在这里插入图片描述
    为了排除打包文件,在 webpack.config.js 中,补充配置

    // 增加代码智能提示
    const { Configuration } = require('webpack')
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    const { VueLoaderPlugin } = require('vue-loader/dist/index')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    const FriendlyErrorsWebpackPlugin = require("friendly-errors-webpack-plugin");
     
    /**
     * @type { Configuration } // 使用注解的方式,增加代码智能提示
     */
    const config = {
        mode: "development",
        // 入口文件
        entry: './src/main.ts',
        // 出口文件
        output: {
            filename: "[hash].js",
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, // 解析 .vue 结尾的文件
                    use: "vue-loader"
                },
                {
                    test: /\.less$/, // 解析 less
                    use: ["style-loader", "css-loader", "less-loader"],
                },
                {
                    test: /\.css$/, // 解析 css
                    use: ["style-loader", "css-loader"],
                },
                {
                    test: /\.ts$/, // 解析 ts
                    loader: "ts-loader",
                    options: {
                        configFile: path.resolve(process.cwd(), 'tsconfig.json'),
                        appendTsSuffixTo: [/\.vue$/]
                    },
                }
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                // 指定 html 模板位置
                template: "./public/index.html"
            }),
            new VueLoaderPlugin(), // 解析 vue 模板
            new CleanWebpackPlugin(), // 打包清空 dist
            new FriendlyErrorsWebpackPlugin({
                compilationSuccessInfo: { // 美化样式
                    messages: ['You application is running here http://localhost:9001']
                }
     
            })
        ],
        // 取消多余的打包提示
        stats: "errors-only",
        resolve: {
            alias: {
                "@": path.resolve(__dirname, './src') // 别名
            },
            extensions: ['.js', '.json', '.vue', '.ts', '.tsx'] // 识别后缀
        },
        // 排除打包 vue,采用 CDN 引入 vue,减小打包体积
        externals: {
            vue: "Vue"
        },
    }
     
    module.exports = config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    配置完成后,重新打包可得 40k+
    在这里插入图片描述

  • 相关阅读:
    园林绿化资质怎么办理,新办园林绿化资质资产要求解读
    Git 开源的版本控制系统-05-tags 标签管理
    第一次前端面试总结(北森一面凉经)
    Mac管理多版本Python(pyenv, virtualenv,anaconda)
    PHP生成图形验证码
    ZEMAX | 探索 OpticStudio中的序列模式
    2022年全国最新消防设施操作员(中级消防设施操作员)真题题库及答案
    CANanlystII 基于linux的二次开发实践
    性能测试脚本用例【模板】
    电子学会2021年3月青少年软件编程(图形化)等级考试试卷(一级)答案解析
  • 原文地址:https://blog.csdn.net/m0_64544033/article/details/132806570