如何搭建一个Webpack5+Vue3+TS的开发环境

575 阅读10分钟

前言

随着TypeScript越来越火,作为一名前端工程师,必须紧跟技术的潮流,最近也学习起了TypeScript,然后通过博客来记录自己的一些学习心得和笔记,同时,这也是本人的第一篇博客,如果有写的不好的地方请大家见谅,如果有错误的地方,也欢迎大家指正; 我们都知道,TypeScript是2012年微软正式发布的一门编程,虽然发布的时间不久,他的热门程度可是不低的,就连前端最火的三大框架都在用TypeScript开发,TypeScrip是JavaScrip的超集,他是在JavaScript语法之上建立的一门语言,同时将其他语言的一些精妙的语法引入了进来,从而把JavaScript带到了一个新的高度,借助TS的扩展语法以及面向对象和静态类型的良好支持,我们可以编写出更健壮更可维护的大型项目;学习TS之前,我们需要先搭建出TS的开发环境,这篇文章,我们将学习如何使用webpack5搭建一个Vue3+TS的项目,方便我们学习TypeScript;

1、新建TS项目

新建一个文件夹,命名如first-typescript,然后初始化工程;

执行命令

git init
npm init-y //忽略所有提问,默认都选Y

根目录下添加.gitignore文件,将node_modules添加进去,避免git没必要的文件追踪;

安装typescript,这里选择全局安装;

npm i typescript -g

引入ts的配置文件;

tsc --init

这个时候文件夹中就会生产一个tsconfig.json文件,打开文件,里面是ts的编译选项及相应的解释;接下来就可以编译ts文件了;

根目录下新建src文件夹,文件夹中新建index.ts文件,简单的写入一下内容;如下:

// index.ts
let hello: string = "Hello TypeScript"

然后编译一下,执行命令;

tsc ./src/index.ts

此时,在文件夹中就会看到一个编译好的js文件,打开文件可以看到以下内容;你会看到let被编译成了var,然后去掉了类型注解;

// index.js
var hello = "Hello TypeScript"

2、搭建开发环境引入ts-loader

以上,一个ts的环境就搭建好了,也可以正常编译ts文件了,接下来我们将使用webpack构建我们的开发环境;

引入相应的包;

npm i webpack webpack-cli webpack-dev-server -D

在根目录下创建一个config文件夹,用来存放我们所有的配置文件,我们知道开发环境和生产环境的配置是不一样的,为了便于维护,我们需要将开发环境和生产环境的配置以及公共配置文件分开,然后通过插件进行合并;

在config文件夹下新建四个配置文件,分别是webpack.base.config.js(公共配置文件)、webpack.dev.config.js(开发环境配置文件)、webpack.pro.config.js(生产环境配置文件)、webpack.config.js(配置文件入口)文件,接下来,我们分别编写各个配置文件的配置;

3、编辑项目配置文件

首先,我们先来编写公共配置文件,因为我们使用了TS,所以要引入相应的loader文件,同时,我们还需要在开发环境中安装下typescript;

执行命令:

npm i typescript ts-loader -D

1)、创建html入口文件

我们还需要一个模板去帮助我们生产网站的首页,同时我们还需要安装html-webpack-plugin插件,然后在配置文件中引入这个插件;

新建html模板文件,在src下新建tpl文件夹,文件夹中新建index.html文件,快速构建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>

安装html-webpack-plugin

npm i html-webpack-plugin -D

2)、公共配置

webpack.base.config.js

const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
    entry: "./src/index.ts", // 入口文件
    output: {
        filename: "app.js", // 输出文件名字
    },
    resolve: {
        extensions: [".js", "ts", "tsx"], // 指定文件扩展名
    },
    module: {
        rules: [
            {
                test: /\.(t|j)s$/, //也可以写成/\.tsx?$/i
                exclude: /node_modules/, // 排除node_modules文件夹
                use: {
                    loader: "ts-loader",
                },
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 这个插件可以通过一个模板帮助我们生成网站的首页,而且可以帮助我们将输入的模板自动嵌入到指定的文件中
            title: "firstTypescript",
            template: "./src/tpl/index.html",
        }),
    ],
}

3)、开发环境配置

然后我们配置开发环境信息,在开发环境中我们开启了sourceMap,这里我们选用了官方推荐的eval-cheap-module-source-map;其中cheap表示sourceMap会忽略文中的列信息,因为我们在调试的时候列信息是没用的,module表示会定位到我们的TS源码而不是经过loader转译的JS源码;evalSourceMap表示会将sourceMap会以DataUrl的形式打包到文件中,他的重编译速度是很快的,所以不用担心性能问题;

module.exports = {
  devtool: 'eval-cheap-module-source-map'
}

4)、生产环境配置

接下来我们配置生产环境信息,开发环境我们使用了一个插件clean-webpack-plugin,他的作用就是在每次构成成功之后帮助我们清空dist目录,因为每次构建之后为了避免缓存,我们需要在构建的文件中加入hash,这样的话在多次构建之后,就会产生很多无用的文件;

执行命令:

npm i clean-webpack-plugin -D

然后在配置文件中引用;

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    plugins: [
        new CleanWebpackPlugin()
    ]
}

2)、配置文件入口

最后,我们编写配置文件的入口,首先我们使用了一个插件webpack-merge来合并配置文件,然后引入刚刚编写的配置文件,将配置文件合并;

安装webpack-merge:

npm i webpack-merge -D

然后根据环境来合并相应的配置文件;

const merge = require("webpack-merge")
const baseConfig = require("./webpack.base.config")
const devConfig = require("./webpack.dev.config")
const proConfig = require("./webpack.pro.config")

module.exports = (env, argv) => {
    let config = argv.mode === "development" ? devConfig : proConfig
    return merge(baseConfig, config)
}

4、修改构建脚本

接下来我们要去修改构建脚本,进入package.json文件,首先更改一下他的入口,将main指定为'./src/index.ts',然后编写项目的启动命令,将其命名为serve,使用webpack-dev-serve插件,然后将当前的环境变量设置为development,然后再指定配置文件;

"scripts": {
    "serve": "webpack-dev-serve --mode=development --config ./config/webpack.config.js"
  },

然后运行项目:

npm run serve

你会发现项目可以正常运行了,然后我们修改index.ts文件来验证一下,将一开始写的"Hello TypeScript"渲染到页面上;

// index.ts
let hello: string = "Hello TypeScript"
document.querySelectorAll('.app')[0].innerHTML = hello;

完成后保存,然后看到页面上能够正常渲染,说明开发环境构建成功;添加生产环境构建命令,取名为build,构建生产环境我们需要使用webpack命令,同样,我们需要设置环境给你参数为production,然后指定配置文件;

"scripts": {
    "serve": "webpack-dev-serve --mode=development --config ./config/webpack.config.js",
    "build": "webpack --mode=production --config ./config/webpack.config.js"
  },

运行npm run build,构成成功,生产了一个dist目录,里面是我们构建之后的文件;

5、提高构建速度

以上,我们借助ts-loader搭建好了一个TS的开发环境,通过t-loader源码可以看出,ts-loader是使用了官方的tsc,ts-loader和tsc是共享tscconfig.json文件的,此外,ts-loader还有一些自己的配置,他是通过options来传入的,他的配置项可以借助ts-loader官方文档来了解,这里我们介绍一个配置项,叫transpileOnly,它的默认值是false,意思就是告诉ts-loader在做语言转换的时候只做语言转换而不进行类型检查,因为在实际的项目中,你会发现随着项目越来越大,构建时间也越来越长,原因之一就是ts编译器要做很多的事情,不仅要做语言转换,还要做类型检查,开启这个配置项,就可以大幅度的提高构建速度;

那么,我们在开启这个配置项的时候如何进行配置检查呢?这里我们要借助一个插件,fork-ts-checker-webpack-plugin,他可以在一个独立的进程中运行,安装插件并引入;

 npm i fork-ts-checker-webpack-plugin -D

在配置文件中引入;

const HtmlWebpackPlugin = require("html-webpack-plugin")
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin")

module.exports = {
    entry: "./src/index.ts", // 入口文件
    output: {
        filename: "app.js", // 输出文件名字
    },
    resolve: {
        extensions: [".js", "ts", "tsx"], // 指定文件扩展名
    },
    module: {
        rules: [
            {
                test: /\.(t|j)s$/, //也可以写成/\.tsx?$/i
                exclude: /node_modules/, // 排除node_modules文件夹
                use: {
                    loader: "ts-loader",
                    options: {
                        transpileOnly: true,
                    },
                },
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 这个插件可以通过一个模板帮助我们生成网站的首页,而且可以帮助我们将输入的模板自动嵌入到指定的文件中
            title: "firstTypescript",
            template: "./index.html",
        }),
        new ForkTsCheckerWebpackPlugin(),
    ],
}

然后在构建过程中就能进行类型检查;

6、使用babel编译TS

除了ts-loader之外,其实我们还可以使用babel-loader来编译ts文件,和ts-loader相比,babel-loader只会对TS文件进行转义不会进行类型检查,所以他的编译速度是很快的,如果要进行类型检查,可以借助IDE来实现,同时开启ts配置项"noEmit": true,只进行类型检查而不编译文件,同时,Babel会根据不同的兼容环境,按需引入pollyfill,比 TSC 直接引入 core-js 更优雅,因此使用了 Babel 打包的体积也会更小。Babel处理TS需要安装@babel/preset-typescript,然后在配置文件中声明;

引入相关依赖:

npm i babel-loader @babel/core @babel/preset-env @babel/preset-typescript -D

修改webpack.base.config.js文件

const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
    entry: "./src/index.ts", // 入口文件
    output: {
        filename: "app.js", // 输出文件名字
    },
    resolve: {
        extensions: [".js", "ts", "tsx"], // 指定文件扩展名
    },
    module: {
        rules: [
            {
                test: /\.(t|j)s$/, //也可以写成/\.tsx?$/i
                exclude: /node_modules/, // 排除node_modules文件夹
                use: {
                    loader: "babel-loader",
                    options: {
                        cacheDirectory: true,
                    },
                },
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 这个插件可以通过一个模板帮助我们生成网站的首页,而且可以帮助我们将输入的模板自动嵌入到指定的文件中
            title: "firstTypescript",
            template: "./index.html",
        }),
    ],
}

7、修改babel配置

跟目录下新建babel.config.js文件

module.exports = {
    presets: [
        "@babel/preset-env",
        [
            "@babel/preset-typescript",
            {
                allExtensions: true, //支持所有文件扩展名
            },
        ],
    ],
}

然后打包项目,发现打包并没有异常,然后允许项目,无异常,这时我们就可以卸载ts-loader了;

8、引入Vue3

最后我们再引入vue3,安装vue3及vue-loader;

npm i vue -S // 2022年2月7号开始,默认安装vue3版本
npm i vue-loader -D

然后在基础配置文件中引入vue-loader;同时,我们还需要引入vue插件,将定义的js, css等规则应用到.vue文件中去;

 const HtmlWebpackPlugin = require("html-webpack-plugin")
 const { VueLoaderPlugin } = require("vue-loader")

module.exports = {
    entry: "./src/index.ts", // 入口文件
    output: {
        filename: "app.js", // 输出文件名字
    },
    resolve: {
        extensions: [".js", "ts", "tsx"], // 指定文件扩展名
    },
    module: {
        rules: [
            {
                test: /\.(t|j)s$/, //也可以写成/\.tsx?$/i
                exclude: /node_modules/, // 排除node_modules文件夹
                use: {
                    loader: "babel-loader",
                    options: {
                        cacheDirectory: true,
                    },
                },
            },
            {
              test: /\.vue$/,
              use: 'vue-loader'
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            // 这个插件可以通过一个模板帮助我们生成网站的首页,而且可以帮助我们将输入的模板自动嵌入到指定的文件中
            title: "firstTypescript",
            template: "./src/tpl/index.html",
        }),
        new VueLoaderPlugin(),
    ],
}

8、编译Vue3

我们在src下新建App.vue文件,写入vue3代码

<template>
    <h1>{{ name }}</h1>
</template>

<script lang="ts">
import { defineComponent } from "vue"

export default defineComponent({
    setup() {
        const name = "vue3 + TypeScript"
        return {
            name,
        }
    },
})
</script>

然后修改index.ts文件

import { createApp } from "vue"
import App from "./App.vue"

createApp(App).mount("#app")

你会发现引入App.vue时编辑器会报错,这是因为ts无法解析.vue文件,需要在src新建一个以.d.ts结尾的类型声明文件;新建vue-shims.d.ts,写入以下代码;

declare module "*.vue" {
    import type { DefineComponent } from "vue"
    const component: DefineComponent<{}, {}, any>
    export default component
}

执行打包命令,这个时候我们会发现报错,这是因为解析.vue文件我们需要引入@vue/compiler-sfc这个包;

npm i @vue/compiler-sfc -D

然后执行打包命令,这下,我们就能打包成功了,然后我们运行项目,在浏览器中,我们就能看到项目已经正常运行了;

9、结语

这样,一个基于webpack+vue3+TS的项目就搭建完成了,当然,正式开发的配置远不止这些,像css,img以及代码格式检查工具ESLint这些我们都还没有配置,这里完成的只是一个很基础的配置,分别介绍了如何使用ts-loader和babel-loader搭建TS开发环境以及他们的区别,至于其他的配置,会在后续的文章中,再一一讲述;