Webpack5 搭建 Vue3 + TS 項目

 

1. 前言

筆者兩年前曾寫過一篇文章《Webpack4 搭建 Vue 項目》,後來隨着 webpack5 和 vue3 的面世,一直想升級下我這個 createVue 項目,可是苦於沒有時間(實際上是由於懶),一直拖延至今。搗鼓了好幾天,終於搭建好整個項目,所以僅以此文記錄升級搭建的過程。html

PS: 其實也能夠用官方腳手架搭建的,爲什麼要本身從頭作起呢?有腳手架我不用,我就折騰。哎,就是玩兒~????前端

2. 準備工做

爲什麼升級?除了折騰外,即是享受新版本帶給咱們的新特性體驗。vue

Webpack5 的新特性node

  • 持久化緩存
  • moduleIds & chunkIds 的優化
  • 更智能的 tree shaking
  • Module Federation
  • ...

Vue3 的新特性

  • 更小
  • 更快
  • 增強 TypeScript 支持
  • 增強 API 設計一致性
  • 提升自身可維護性
  • 開放更多底層功能

肯定項目技術棧

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

3. 項目搭建

此文並非從零搭建,而是在 createVue@v1.0.0 的基礎上修改搭建,如若看不懂,能夠先看《Webpack4 搭建 Vue 項目》,跟着一步步搭建,後再看此文升級webpack

建立 createVue 文件夾,進入該文件夾, npm init 初始化項目ios

老規矩,安裝 webpack 四件套npm i webpack webpack-cli webpack-dev-server webpack-merge --save-devgit

當前使用版本:
"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 啓動開發服務器命令與以前有所變化,從 webpack-dev-server 轉變爲 webpack serve, 所以 package.json 中 script 的 start 修改成: "start": "webpack serve --progress --hot --inline --config build/webpack.dev.js"github

  1. 建立相應文件

與以前沒有太大差別。增長變更的有一下幾點:web

1). 持久化緩存,增長 cache 配置. v5 中緩存默認是 memory,修改設置"filesystem"寫入硬盤vue-router

// 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-sfc, vue-loader 保持不變。 npm i vue-loader @vue/compiler-sfc --save-dev

// 當前我使用版本
"vue-loader": "^16.2.0",
"@vue/compiler-sfc": "^3.0.11",

安裝 vue3 及相關庫,添加 vue 類型文件

npm i vue@next vuex@4.0.0-rc.1 vue-router --save

src 文件夾下添加 shims-vue.d.ts 文件,解決 vue 類型報錯

// 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編譯配置,爲了區分腳本的ts配置
          configFile: path.resolve(__dirname, '../tsconfig.loader.json'),
          // 對應文件添加個.ts或.tsx後綴
          appendTsSuffixTo: [/\.vue$/],
        },
      },
    ],
}

ts-loader 爲單進程執行類型檢查和轉譯,所以效率有些慢,能夠用多進程方案:即關閉ts-loader的類型檢查,類型檢查由 fork-ts-checker-webpack-plugin 插件執行。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編譯配置,爲了區分腳本的ts配置
          configFile: path.resolve(__dirname, '../tsconfig.loader.json'),
          // 對應文件添加個.ts或.tsx後綴
          appendTsSuffixTo: [/\.vue$/],
          transpileOnly: true, // ? 關閉類型檢查,即只進行轉譯
        },
      },
    ],
}
// plugins push
new ForkTsCheckerWebpackPlugin()

至此項目基本能夠跑起來了,那麼有個問題了:Ts 能夠編譯爲指定版本的 js,那麼還須要 babel 麼?

tsc 的 target 只轉譯語法,不集成 polyfill,因此仍是得要 babel。

好比把箭頭函數轉成普通 function、aysnc + await 變成 Promise.then,這是語法轉譯;

但你運行環境裏若是沒有 Promise.prototype.finally,那沒有就仍是沒有。

所以咱們項目裏仍是須要 babel.

Webpack 轉譯 Typescript 現有方案:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

在 babel7 以前,是須要同時使用 ts-loader 和 babel-loader 的,其編譯過程 TS > TS 編譯器 > JS > Babel > JS 。可見編譯了兩次js,效率有些低下。可是 babel7 出來以後有了解析 typescript 的能力,有了這一層面的支持,咱們就能夠只使用 babel,而不用再加一輪 ts 的編譯流程了。

在 babel 7 中,咱們使用新的 @babel/preset-typescript 預設,結合一些插件即可以解析大部分的 ts 語法。

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

Babel 刪除了全部 TypeScript,將其轉換爲常規的 JavaScript,並繼續以它本身的方式處理。刪除了 typescript 則不須要進行類型檢查,不會有煩人的類型錯誤提醒,所以編譯速度提高,開開心心編程????

固然,類型安全性檢查必不可少,咱們能夠統一在某個時間集中處理,增長 script:

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

添加 babel 解析 typescript

# 安裝如下依賴 --save-dev
# webpack loader
babel-loader
# babel 核心
@babel/core
# 智能轉換成目標運行環境代碼
@babel/preset-env
# 解析 typescript 的 babel 預設
@babel/preset-typescript
# polyfill 
@babel/plugin-transform-runtime
# 支持 ts 類的寫法
@babel/plugin-proposal-class-properties 
# 支持三點展開符
@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',
      },
    ],
}

項目根目錄添加 babel 配置文件 babel.config.js

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage', // 按需引入 polyfill
        corejs: 3,
      },
    ],
    [
      '@babel/preset-typescript', // 引用Typescript插件
      {
        allExtensions: true, // 支持全部文件擴展名,不然在vue文件中使用ts會報錯
      },
    ],
  ],
  plugins: [
    [
      '@babel/plugin-transform-runtime',
      {
        corejs: 3,
      },
    ],
    '@babel/proposal-class-properties',
    '@babel/proposal-object-rest-spread',
  ],
}

4. 代碼規範

項目中代碼規範集成了 EditorConfig, Prettier, ESLint, Husky, Lint-staged,以及如何解決 Prettier 和 ESLint 的衝突的問題,具體實現能夠參考 《從 0 開始手把手帶你搭建一套規範的 Vue3.x 項目工程環境》這篇文章,講的很詳細這裏再也不贅述。

5. 提交規範

利用 inquirer 選擇配置好的提交類型,以及配合 commitlint 實現 commit 檢查

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

添加 package.json 的 script :

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

建立 commit/git-commit.js 文件

const shell = require('shelljs')
const inquirer = require('inquirer')
const prompsConfig = {
  ciType: [
    {
      type: 'list',
      name: 'type',
      message: '請選擇本次提交的類型:',
      choices: [
        {
          name: '引入新特性',
          value: 'feat',
        },
        {
          name: '改進代碼的結構格式/樣式',
          value: 'style',
        },
        {
          name: '修復 bug',
          value: 'fix',
        },
        {
          name: '提高性能',
          value: 'perf',
        },
        {
          name: '刪除代碼或文件',
          value: 'delete',
        },
        {
          name: '其餘修改, 好比改變構建流程、或者增長依賴庫、工具等',
          value: 'chore',
        },
        {
          name: '重構',
          value: 'refactor',
        },
        {
          name: '撰寫文檔',
          value: 'docs',
        },
        {
          name: '增長測試',
          value: 'test',
        },
        {
          name: '更新打包文件',
          value: 'build',
        },
        {
          name: '初次提交',
          value: 'init',
        },
        {
          name: '發佈/版本標籤',
          value: 'release',
        },
        {
          name: '部署功能',
          value: 'deploy',
        },
        {
          name: '代碼回滾',
          value: 'revert',
        },
        {
          name: 'CI持續集成修改',
          value: 'ci',
        },
      ],
    },
  ],
  ciMsg: {
    type: 'input',
    name: 'msg',
    message: '請輸入提交文本:',
    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 類型,建立 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 相關文件,執行 npm run commit 便可執行 commit 校驗

6. 構建部署 Travis CI

Travis CI 是一款構建和測試的自動化工具,不只能夠提升效率,還能使開發流程更可靠和專業化,從而提升軟件的價值。並且,它對於開源項目是免費的,不花一分錢,就能幫你作掉不少事情。詳細介紹能夠查看 阮一峯——《持續集成服務 Travis CI 教程》

首先,訪問官方網站 travis-ci.org,點擊右上角的我的頭像,使用 Github 帳戶登入 Travis CI。

找到對應的倉庫,打開開關添加倉庫

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

點擊對應倉庫的 setting

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

設置環境變量 GITHUB_TOKEN 爲剛纔 github 處生成的 token

建立 .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 推送代碼到你的倉庫。
  # 在倉庫對應的 Travis 設置頁面中配置,用於安全控制。
  github_token: $GITHUB_TOKEN
  keep_history: true
  on:
    branch: master

這樣,當你 push 到 master 或者 pr 合併到 master 的時候,就會觸發部署腳本的執行,將生成的 dist 推送至 gh-pages 分支

7. 存在問題及總結

  • 構建時間比 webpack4 長,多是因爲 ts 的引入,以及 happypack 多進程構建的移除形成時間略長
  • dev server 不會自增 port
  • fork-ts-checker-webpack-plugin 沒法檢測 vue 中的 ts 類型錯誤

搗鼓了挺長一段時間,也瞭解了蠻多工程化的東西,雖然不必定能用於實際項目中,但仍是算有所收穫吧!

 

END

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

推薦閱讀  點擊標題可跳轉

5個常問的 Vue3 優點點

不要再用 Vue2 的思惟寫 Vue3 了

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
相關文章
相關標籤/搜索