1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        使用 Webpack5 創(chuàng)建 Vue3 + TS 項(xiàng)目

        共 15529字,需瀏覽 32分鐘

         ·

        2021-05-20 15:33

        作者:suporka

        https://segmentfault.com/q/1010000024459339

        1. 前言

        筆者兩年前曾寫(xiě)過(guò)一篇文章《Webpack4 搭建 Vue 項(xiàng)目》,后來(lái)隨著 webpack5 和 vue3 的面世,一直想升級(jí)下我這個(gè) createVue 項(xiàng)目,但是苦于沒(méi)有時(shí)間(其實(shí)是因?yàn)閼校?,一直拖延至今。搗鼓了好幾天,終于搭建好整個(gè)項(xiàng)目,因此僅以此文記錄升級(jí)搭建的過(guò)程。

        PS: 其實(shí)也可以用官方腳手架搭建的,為何要自己從頭做起呢?有腳手架我不用,我就折騰。哎,就是玩兒~??

        2. 準(zhǔn)備工作

        為何升級(jí)?除了折騰外,便是享受新版本帶給我們的新特性體驗(yàn)。

        Webpack5 的新特性

        • 持久化緩存
        • moduleIds & chunkIds 的優(yōu)化
        • 更智能的 tree shaking
        • Module Federation
        • ...

        Vue3 的新特性

        • 更小
        • 更快
        • 加強(qiáng) TypeScript 支持
        • 加強(qiáng) API 設(shè)計(jì)一致性
        • 提高自身可維護(hù)性
        • 開(kāi)放更多底層功能

        確定項(xiàng)目技術(shù)棧

        • 編程語(yǔ)言:TypeScript 4.2.4
        • 構(gòu)建工具:[Webpack 5.33.2]()
        • 前端框架:Vue 3.0.11
        • 路由工具:Vue Router 4.0.6
        • 狀態(tài)管理:Vuex 4.0.0
        • CSS 預(yù)編譯:Sass / Less
        • HTTP 工具:Axios
        • Git Hook 工具:Husky + Lint-staged
        • 代碼規(guī)范:EditorConfig + Prettier + ESLint
        • 提交規(guī)范:Commitlint
        • 構(gòu)建部署:Travis

        3. 項(xiàng)目搭建

        此文并不是從零搭建,而是在 [email protected] 的基礎(chǔ)上修改搭建,如若看不懂,可以先看《Webpack4 搭建 Vue 項(xiàng)目》,跟著一步步搭建,后再看此文升級(jí)

        創(chuàng)建 createVue 文件夾,進(jìn)入該文件夾, npm init 初始化項(xiàng)目

        老規(guī)矩,安裝 webpack 四件套npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev

        當(dāng)前使用版本:
        "webpack""^5.33.2",
        "webpack-bundle-analyzer""^4.4.1",
        "webpack-cli""^4.6.0",
        "webpack-dev-server""^3.11.2",
        "webpack-merge""^5.7.3",

        webpack5 啟動(dòng)開(kāi)發(fā)服務(wù)器命令與之前有所變化,從 webpack-dev-server 轉(zhuǎn)變?yōu)?nbsp;webpack serve, 因此 package.json 中 script 的 start 修改為: "start": "webpack serve --progress --hot --inline --config build/webpack.dev.js"

        1. 創(chuàng)建相應(yīng)文件

        與之前沒(méi)有太大差異。增加變動(dòng)的有一下幾點(diǎn):

        1). 持久化緩存,增加 cache 配置. v5 中緩存默認(rèn)是 memory,修改設(shè)置"filesystem"寫(xiě)入硬盤(pán)

        // webpack.dev.js
        module.exports = merge(common, {
          cache: {
            type'filesystem',
          }
          //...
        }

        2). 去除插件 clean-webpack-plugin(v5支持),webpack.HashedModuleIdsPlugin(v5更好的 moduleIds & chunkIds),HardSourceWebpackPlugin(v5支持),happypack(v5不兼容)

        安裝 vue 核心解析插件

        解析插件有所不同,從 vue-template-compiler 變成了 @vue/compiler-sfcvue-loader 保持不變。 npm i vue-loader @vue/compiler-sfc --save-dev

        // 當(dāng)前我使用版本
        "vue-loader""^16.2.0",
        "@vue/compiler-sfc""^3.0.11",

        安裝 vue3 及相關(guān)庫(kù),添加 vue 類(lèi)型文件

        npm i vue@next [email protected] vue-router --save

        src 文件夾下添加 shims-vue.d.ts 文件,解決 vue 類(lèi)型報(bào)錯(cuò)

        // shims-vue.d.ts
        declare module '*.vue' {
          import type { DefineComponent } from 'vue'
          const component: DefineComponent<{}, {}, any>
          export default component
        }

        安裝 html 模板解析插件

        npm i html-webpack-plugin --save-dev

        安裝 typescript 及解析插件

        npm i typescript ts-loader --save-dev

        配置ts-loader解析:

        // webpack.base.js
        // rules
        {
            test: /\.(t|j)s$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'ts-loader',
                options: {
                  // 指定特定的ts編譯配置,為了區(qū)分腳本的ts配置
                  configFile: path.resolve(__dirname, '../tsconfig.loader.json'),
                  // 對(duì)應(yīng)文件添加個(gè).ts或.tsx后綴
                  appendTsSuffixTo: [/\.vue$/],
                },
              },
            ],
        }

        ts-loader 為單進(jìn)程執(zhí)行類(lèi)型檢查和轉(zhuǎn)譯,因此效率有些慢,可以用多進(jìn)程方案:即關(guān)閉ts-loader的類(lèi)型檢查,類(lèi)型檢查由 fork-ts-checker-webpack-plugin 插件執(zhí)行。npm i fork-ts-checker-webpack-plugin --save-dev

        // webpack.base.js
        // rules
        {
            test: /\.(t|j)s$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'ts-loader',
                options: {
                  // 指定特定的ts編譯配置,為了區(qū)分腳本的ts配置
                  configFile: path.resolve(__dirname, '../tsconfig.loader.json'),
                  // 對(duì)應(yīng)文件添加個(gè).ts或.tsx后綴
                  appendTsSuffixTo: [/\.vue$/],
                  transpileOnly: true, // ? 關(guān)閉類(lèi)型檢查,即只進(jìn)行轉(zhuǎn)譯
                },
              },
            ],
        }
        // plugins push
        new ForkTsCheckerWebpackPlugin()

        至此項(xiàng)目基本可以跑起來(lái)了,那么有個(gè)問(wèn)題了:Ts 可以編譯為指定版本的 js,那么還需要 babel 么?

        tsc 的 target 只轉(zhuǎn)譯語(yǔ)法,不集成 polyfill,所以還是得要 babel。

        比如把箭頭函數(shù)轉(zhuǎn)成普通 function、aysnc + await 變成 Promise.then,這是語(yǔ)法轉(zhuǎn)譯;

        但你運(yùn)行環(huán)境里如果沒(méi)有 Promise.prototype.finally,那沒(méi)有就還是沒(méi)有。

        因此我們項(xiàng)目里還是需要 babel.

        Webpack 轉(zhuǎn)譯 Typescript 現(xiàn)有方案:

        綜合考慮性能和擴(kuò)展性,目前比較推薦的是 babel+fork-ts-checker-webpack-plugin 方案。

        在 babel7 之前,是需要同時(shí)使用 ts-loader 和 babel-loader 的,其編譯過(guò)程 TS > TS 編譯器 > JS > Babel > JS ??梢?jiàn)編譯了兩次js,效率有些低下。但是 babel7 出來(lái)之后有了解析 typescript 的能力,有了這一層面的支持,我們就可以只使用 babel,而不用再加一輪 ts 的編譯流程了。

        在 babel 7 中,我們使用新的 @babel/preset-typescript 預(yù)設(shè),結(jié)合一些插件便可以解析大部分的 ts 語(yǔ)法。

        那么,Babel 是如何處理 TypeScript 代碼的呢?

        Babel 刪除了所有 TypeScript,將其轉(zhuǎn)換為常規(guī)的 JavaScript,并繼續(xù)以它自己的方式處理。刪除了 typescript 則不需要進(jìn)行類(lèi)型檢查,不會(huì)有煩人的類(lèi)型錯(cuò)誤提醒,因此編譯速度提升,開(kāi)開(kāi)心心編程??

        當(dāng)然,類(lèi)型安全性檢查必不可少,我們可以統(tǒng)一在某個(gè)時(shí)間集中處理,增加 script:

        "check-types""tsc --watch",

        添加 babel 解析 typescript

        # 安裝以下依賴 --save-dev
        # webpack loader
        babel-loader
        # babel 核心
        @babel/core
        # 智能轉(zhuǎn)換成目標(biāo)運(yùn)行環(huán)境代碼
        @babel/preset-env
        # 解析 typescript 的 babel 預(yù)設(shè)
        @babel/preset-typescript
        # polyfill 
        @babel/plugin-transform-runtime
        # 支持 ts 類(lèi)的寫(xiě)法
        @babel/plugin-proposal-class-properties 
        # 支持三點(diǎn)展開(kāi)符
        @babel/plugin-proposal-object-rest-spread

        # 安裝以下依賴 --save
        @babel/runtime
        @babel/runtime-corejs3
        "core-js""^3.11.0",

        刪除 ts-loader, 添加 babel-loader

        {
            test: /\.(t|j)s$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
              },
            ],
        }

        項(xiàng)目根目錄添加 babel 配置文件 babel.config.js

        module.exports = {
          presets: [
            [
              '@babel/preset-env',
              {
                useBuiltIns: 'usage', // 按需引入 polyfill
                corejs: 3,
              },
            ],
            [
              '@babel/preset-typescript', // 引用Typescript插件
              {
                allExtensions: true, // 支持所有文件擴(kuò)展名,否則在vue文件中使用ts會(huì)報(bào)錯(cuò)
              },
            ],
          ],
          plugins: [
            [
              '@babel/plugin-transform-runtime',
              {
                corejs: 3,
              },
            ],
            '@babel/proposal-class-properties',
            '@babel/proposal-object-rest-spread',
          ],
        }

        4. 代碼規(guī)范

        項(xiàng)目中代碼規(guī)范集成了 EditorConfig, Prettier, ESLint, Husky, Lint-staged,以及如何解決 Prettier 和 ESLint 的沖突的問(wèn)題,具體實(shí)現(xiàn)可以參考 《從 0 開(kāi)始手把手帶你搭建一套規(guī)范的 Vue3.x 項(xiàng)目工程環(huán)境》這篇文章,講的很詳細(xì)這里不再贅述。

        5. 提交規(guī)范

        利用 inquirer 選擇配置好的提交類(lèi)型,以及配合 commitlint 實(shí)現(xiàn) commit 檢查

        npm i inquirer shelljs @commitlint/{cli,config-conventional} -D

        添加 package.json 的 script :

        "commitlint""commitlint -e"
        "commit""node commit/git-commit.js"

        創(chuàng)建 commit/git-commit.js 文件

        const shell = require('shelljs')
        const inquirer = require('inquirer')
        const prompsConfig = {
          ciType: [
            {
              type'list',
              name: 'type',
              message: '請(qǐng)選擇本次提交的類(lèi)型:',
              choices: [
                {
                  name: '引入新特性',
                  value: 'feat',
                },
                {
                  name: '改進(jìn)代碼的結(jié)構(gòu)格式/樣式',
                  value: 'style',
                },
                {
                  name: '修復(fù) bug',
                  value: 'fix',
                },
                {
                  name: '提升性能',
                  value: 'perf',
                },
                {
                  name: '刪除代碼或文件',
                  value: 'delete',
                },
                {
                  name: '其他修改, 比如改變構(gòu)建流程、或者增加依賴庫(kù)、工具等',
                  value: 'chore',
                },
                {
                  name: '重構(gòu)',
                  value: 'refactor',
                },
                {
                  name: '撰寫(xiě)文檔',
                  value: 'docs',
                },
                {
                  name: '增加測(cè)試',
                  value: 'test',
                },
                {
                  name: '更新打包文件',
                  value: 'build',
                },
                {
                  name: '初次提交',
                  value: 'init',
                },
                {
                  name: '發(fā)布/版本標(biāo)簽',
                  value: 'release',
                },
                {
                  name: '部署功能',
                  value: 'deploy',
                },
                {
                  name: '代碼回滾',
                  value: 'revert',
                },
                {
                  name: 'CI持續(xù)集成修改',
                  value: 'ci',
                },
              ],
            },
          ],
          ciMsg: {
            type'input',
            name: 'msg',
            message: '請(qǐng)輸入提交文本:',
            validate: function (value) {
              if (value) {
                return true
              }
              return '文本必須輸入!'
            },
          },
        }

        async function gitCommit() {
          let { type } = await inquirer.prompt(prompsConfig.ciType)
          let { msg } = await inquirer.prompt(prompsConfig.ciMsg)

          shell.exec(`git commit -m "${type}${msg}"`, function () {
            console.log(`\n提交腳本: git commit -m "${type}${msg}"`)
          })
        }

        gitCommit()

        配置 commitlint 類(lèi)型,創(chuàng)建 commitlint.config.js 文件:

        module.exports = {
          extends: ['@commitlint/config-conventional'],
          rules: {
            'type-enum': [2, 'always', [
              'build''chore''ci''feat''docs''fix''perf''revert''refactor''style''test''init''build''release''delete'
             ]],
          }
        };

        完成上述操作后,git add 相關(guān)文件,執(zhí)行 npm run commit 即可執(zhí)行 commit 校驗(yàn)

        6. 構(gòu)建部署 Travis CI

        Travis CI 是一款構(gòu)建和測(cè)試的自動(dòng)化工具,不僅可以提高效率,還能使開(kāi)發(fā)流程更可靠和專(zhuān)業(yè)化,從而提高軟件的價(jià)值。而且,它對(duì)于開(kāi)源項(xiàng)目是免費(fèi)的,不花一分錢(qián),就能幫你做掉很多事情。詳細(xì)介紹可以查看 阮一峰——《持續(xù)集成服務(wù) Travis CI 教程》

        首先,訪問(wèn)官方網(wǎng)站 travis-ci.org,點(diǎn)擊右上角的個(gè)人頭像,使用 Github 賬戶登入 Travis CI。

        找到對(duì)應(yīng)的倉(cāng)庫(kù),打開(kāi)開(kāi)關(guān)添加倉(cāng)庫(kù)

        在 github 上 setting/Developer settings/Personal access token 處生成 travis token

        <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/69ea45bccd674eaeb7023ea850aa2be1~tplv-k3u1fbpfcp-watermark.image" width="700"/>

        點(diǎn)擊對(duì)應(yīng)倉(cāng)庫(kù)的 setting

        設(shè)置環(huán)境變量 GITHUB_TOKEN 為剛才 github 處生成的 token

        <img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a1594556dfc3449698070dfb99c18f59~tplv-k3u1fbpfcp-watermark.image" width="700"/>

        創(chuàng)建 .travis.yml 配置文件:

        language: node_js
        node_js:
          - 12
        branchs:
          only:
            - master
        cache:
          directories:
            - node_modules
        install:
          - yarn install
        scripts:
          - yarn build
        deploy:
          provider: pages
          local_dir: dist
          skip_cleanup: true
          # 在 GitHub 上生成的令牌,允許 Travis 推送代碼到你的倉(cāng)庫(kù)。
          # 在倉(cāng)庫(kù)對(duì)應(yīng)的 Travis 設(shè)置頁(yè)面中配置,用于安全控制。
          github_token: $GITHUB_TOKEN
          keep_history: true
          on:
            branch: master

        這樣,當(dāng)你 push 到 master 或者 pr 合并到 master 的時(shí)候,就會(huì)觸發(fā)部署腳本的執(zhí)行,將生成的 dist 推送至 gh-pages 分支

        <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1710d33f1a1c4da18ad28ef2c4805f34~tplv-k3u1fbpfcp-watermark.image" width="700"/>

        7. 存在問(wèn)題及總結(jié)

        • 構(gòu)建時(shí)間比 webpack4 長(zhǎng),可能是由于 ts 的引入,以及 happypack 多進(jìn)程構(gòu)建的移除造成時(shí)間略長(zhǎng)
        • dev server 不會(huì)自增 port
        • fork-ts-checker-webpack-plugin 無(wú)法檢測(cè) vue 中的 ts 類(lèi)型錯(cuò)誤

        搗鼓了挺長(zhǎng)一段時(shí)間,也了解了蠻多工程化的東西,雖然不一定能用于實(shí)際項(xiàng)目中,但還是算有所收獲吧!

        瀏覽 88
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91午夜影院 | 亚洲激情在线无码 | 国产激情在线观看 | 日韩爱爱爱爱 | 三级黄色操逼视频 | 欧洲性爱在线 | 国产福利网| 日本综合在线 | 美女被cao视频在线观看 | 欧美一区二区三区婷婷五月 |