Vue2 從 Webpack4 遷移到 Vite

Lastor
Code 隨筆放置場
33 min readOct 1, 2023

前陣子幫公司完成了 Vue2 老專案升級。從 node10 升到 node16,並從 @rails/webpacker (webpack4) 成功遷移到了 vite。

這篇來給自己紀錄一下。

## 目錄

- 情境介紹
- 關於 Rails Webpacker
- 重建 Node.js Webpack Config
- @rails/webpacker 依賴 node-sass
- 棄用 @babel/polyfill
- postcss-loader 的順序
- postcss 插件 autoprefixer 與 browserslist
- 處理 css 要區分 dev 與 build
- 遷移到 Vite
- import 需加上 .vue 副檔名
- sass 的 /deep/ 寫法變更
- sass v2 棄用顯示數學計算
- 在 css import node_modules
- jsx 用法變更
- process.env 不可用
- vite 不支援 CommonJS 需改為 ESM
- vite build 需另外設定處理 CommonJS
- webpack require.context() 不可用
- vite 與 webpack5 不再提供 path 等 polyfill
- 處理 css :export
- 替代 webpack svg-sprite-loader
- pnpm ignore missing peer 警告
- build 後 el-table 呈現空白
- element-ui 自訂 theme 被 umy-ui 搶 css 權重
- vite 中 template whitespace 間隔消失
- ES6+ 語法出現 VScode ts 報錯

情境介紹

# 專案環境

- Ruby on Rails 前後端共構專案 (使用 Webpacker)
- 前端透過 @rails/webpacker 構建 Vue2
- node10,有 node-sass
- 當前是 Server build,Node.js 版本被 Server 限制

一直以來這個前端專案就很想脫離 Rails 的掌控,分離出來獨立維護。前端環境從 node14 開始有了許多的變化,Node.js 不再能無腦向下兼容。

最近紛紛出現使用 Mac M1 的同事,遇上了 node10 無法安裝的問題,再加上 node-sass 等舊套件已被棄用,無法運作於 node12 以上環境等因素,早晚都得面對專案升級的問題。

於是,趁著工作的空閒期,嘗試將專案升級。目標大致如下:

- 升級 Node.js 版本,至少到 14 or 16
- 脫離 @rails/webpacker 依賴
- 前後端 git repo 分離
- 遷移至 Vite

關於 Rails Webpacker

先說明一下 Rails Webpacker 這玩意是啥,它是類似 vue-cli、create-react-app 那種 webpack 腳手架,不過是 Ruby on Rails 的版本,但它已不再維護。

當前版本內部使用 webpack4,並內置 node-sass 等等,當時主流的前端工具。由於它是針對 Rails 來建構的,所以會出現一些前端不熟悉的配置。

不過 webpack 配置本質上都是差不多的,只要搞清楚 config 在哪、html 進入點、js 進入點這些東西,就能夠重架一個 Node.js 主導的 webpack 配置。

先網上查詢關於 Rails Webpacker 的文章,然後找出核心配置有哪些,其他的可以不用太深入。

對照此專案的情況,可以整理出這些檔案。

# rails webpacker 設定檔
config/webpacker.yml

# 終端機 cli 的執行檔
bin/webpack
bin/webpack-dev-server

# webpack 設定檔
config/webpack/custom.js (非預設)
config/webpack/environment.js
config/webpack/development.js
config/webpack/production.js
// ...

# js 進入點
app/javascript/pack/application.js
app/javascript/pack/main.js (非預設)

# vue 的 source files
app/javascript/src/**/*

# html 進入點
app/views/layouts/application.html.erb
app/views/layouts/vue.html.erb (非預設)
app/views/vue/index.html.erb

在 webpacker 的設定檔 config/webpacker.yml 可以找到 inpurt 與 output 設定。

# config/webpacker.yml
source_path: app/javascript
source_entry_path: packs
public_root_path: public
public_output_path: packs

source_xxx 得知 input 在 app/javascript/packs/* 底下,似乎預設會是 application.js,但我這專案改成了 main.js。而 output 則會根據 public_xxx 的設定 build 到 public/packs/*

執行檔是用 rails cli 指令,進行 dev 啟動或 build 時,會根據那兩個檔案的內容去調用 webpack。

# 縮寫 rails s, 後端 dev 啟動
# 進到 vue 頁面會執行 bin/webpack
$ rails server

# 依據 Procfile 的設定同時啟動前後端 dev server
# 這邊會調用 bin/webpack-dev-server
$ foreman start

# 前端 build
rake assets:precompile

再來是 webpack 的設定檔,裡面有很多個,但從命名可以看出那只是區分成 development、production、test 不同模式而已。

從內容可以推斷出核心檔案是 environment.js,不同模式的檔案都會引入它。我這專案有另外寫一個 custom.js,這支會在 environment.js 被引入,用來覆蓋預設設定。

custom.js 這支檔案的寫法與 webpack config 是一樣的,所以就可以從這支檔案得知具體設定。

js 進入點沒甚麼特別的機制,但 html 進入點就比較麻煩,因為他是 .erb 檔,可以視作 Rails 的模板文件,它會接收一些從 Rails render 出來的內容。

大概是長這樣。

<!-- app/views/layouts/vue.html.erb -->
<head>
<%= javascript_pack_tag 'main' %>
<%= stylesheet_pack_tag 'main' %>
<%= csrf_meta_tags %>
<!-- ... -->
</head>

<body>
<div class="container" data-behavior="app">
<%= render 'path/to/file' %>
<%= yield %>
</div>
</body>

那些看起來奇怪的 html <%= … %> 是 erb 的模板語法。head 裡面的 javascript_pack_tag 是指定在這邊塞 webpack 編譯後的 js 檔,顧名思義,這段會去 app/javascript/pack/* 底下尋找 main.js。而後面兩個我這專案實際運行確認是空的,所以不理它。

body 底下的 render 從命名可以看出,這邊是插入指定的模板組件進來。我這專案引入的只是一塊版本資訊的 banner,先不理它,之後可以在 Vue 裡面重做。

另一個 yield,則會導入 rails contoller 定義的模板。

# app/controllers/vue_controller.rb
class VueController < ApplicationController
layout 'vue'
def index
end
end

# app/views/vue/index.html.erb
<div id="app"></div>

layout 'vue' 指的是 app/views/* 底下的 vue 資料夾,然後再指向裡面的 index.html.erb

確認 Rails 注入的東西有哪些之後,就可以改寫回單純的 index.html 了。

如此,進入點都找到了,也有 config 了,那就可以進入下一步。

重建 Node.js Webpack Config

先嘗試重建 webpack config,讓 Node.js 可以執行 dev 啟動以及 build,脫離 Rails 控制。

除了上述的核心檔案之外,也別忘了根目錄底下各式 js 相關的 config:

# npm & js 設定
package.json
yarn-lock (or package-lock.json or pnpm-lock.yaml)
jsconfig.json (or tsconfig.json)
.nvmrc

# babel (JS 編譯器)
.babelrc

# postcss (css 後處理器)
postcss.config.js
.browserslistrc

# eslint (風格規範)
.eslintignore
.eslintrc.js

# prettier (auto formatter)
.prettierrc.js

原本 webpack 是 @rails/webacker 底下的子依賴,實際並沒有安裝。

需先補安裝。可以在 lock 檔確認 @rails/webpacker 使用的 webpack 版本。

$ yarn add webpack@"^4.41.2"
$ yarn add webpack-cli@"^3.3.10"
$ yarn add webpack-dev-server@"3.10.1"

補上 npm scripts。

// package.json
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack --mode production"
// ...
}

接著新增 webpack.config.js,把 config/webpack/custom.js 搬過來,就可以嘗試啟動,進入除錯之旅。

但我因為想順便複習一下 webpack,所以找了一篇教學從零一個一個去設定。

我這專案的情況,照這教學做完,再跟原本 custom.js 的設定核對之後,就能順利啟動了。

webpack 這玩意麻煩在它不是開箱即用的,幾乎所有設定都要自己去弄。不過概念上也不複雜,就是每一個 assets 都要告訴 webpack 要如何解析。無非就是指定 css 使用這個 loader,img 使用那個 loader,然後設定細節。

確認 Node.js 端啟動沒問題之後,可以新建 repo 搬過去了,不確定的話就直接抄 vite 或 vue-cli 的目錄結構。

# 新建專案

public
favicon.ico
logo.svg
src
...
App.vue
main.js # 原本在 rails 是單獨放置, 現在將它放到 src 裡面
index.html
...configs

搬移之後,修改 webpack config 的 entry、output、alias 那些路徑。

接著移除 @rails/webpacker

$ yarn remove @rails/webpacker

再嘗試啟動,由於 webpacker 內包的子依賴已移除,會發現需要補裝一些套件,我的情況是這些:

{
"node-sass": "^4.14.1",
"postcss": "^7.0.39",
"postcss-flexbugs-fixes": "^4.2.1",
"postcss-import": "^12.0.1",
"postcss-preset-env": "^6.7.0",
"sass-loader": "^7.3.1",
}

現在,已經成功將前端獨立拆了出來,脫離了 Rails Webpacker 依賴。再來就是系統升級了。

移除 node-sass,更換為 sass。它的兼容性很強,可以無腦安裝最新版,當前是 v1.66.1。

$ yarn remove node-sass
$ yarn add sass

這邊要注意一下,換成 sass 之後原本 /deep/ 的寫法被棄用,需要改成 :deep,直接 VSCode 搜尋替換就好。

/* node-sass */
/deep/.my-style {}

/* sass */
:deep .my-style {}

接著升級 Node.js。用 nvm 之類的版本管理器切換到 node16,然後移除 node_modulesyarn-lock 重裝套件。並依喜好,順道將 yarn 更換成 pnpm。

# 切換 node16
$ nvm install 16
$ nvm use 16

# 啟用 pnpm 並更新到最新
$ corepack enable
$ corepack prepare pnpm@latest --activate

# 以 node16 與 pnpm 重裝套件
$ pnpm install

然後測試 dev 啟動以及 build,確認沒問題之後就告個段落。

成功完成了:

  • Node.js 升級至 v16
  • 脫離 @rails/webpacker 與 node-sass 依賴
  • 前後端分離

流水帳記錄一下 webpack config 重建遇上的坑。

@rails/webpacker 依賴 node-sass

node-sass,只能運行在 node12 以下版本。這是因為它使用了 node-gyp 牽扯到 python 一些雜七雜八的。Mac M1 由於架構不同會裝不上去。

升級到 node14+ 之後,只要將套件換成 sass 就行了,webpack 的話要記得 sass-loader 也要升。

棄用 @babel/polyfill

babel 7.4.0 開始棄用 @babel/polyfill,改用 @babel/preset-env,設定方式不一樣。前者會寫在 webpack config 上,後者會寫在 babel config 上。

postcss-loader 的順序

webpack 的 loader 設定採用 Array,但執行順序是「反著來的」,它會從後面的 loader 先開始解析。

所以使用 Sass + postcss 時,postcss-loader 要放在 sass-loader 的前面,先解析 Sass 完成之後,postcss 才能接手。

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

postcss 插件 autoprefixer 與 browserslist

autoprefixer 透過 postcss 驅動,幫 css 添加 -webkit- 這些兼容性前綴。同時它會根據 .browserslistrc 的設定編譯成不同內容。

browserslist 這玩意也會影響到 babel,如果指定兼容比較舊的瀏覽器,會造成 ?. 以及 ?? 這些 js 新語法在編譯時報錯,需要補裝相關 plugin。

# 處理 ?.
@babel/plugin-transform-optional-chaining

# 處理 ??
@babel/plugin-transform-nullish-coalescing-operator

然後這個 autoprefixer 在 postcss 新版本已可用 postcss-preset-env 取代。

處理 css 要區分 dev 與 build

啥都不設定的話,webpack 預設會將 css 打包到 js 裡面,造成 js 過度肥大。

dev 啟動一般會用 style-loader (vue 使用 vue-style-loader) 將 css 編譯到 <style> 裡面往 html 塞。

build 則會希望打包成獨立的 .css file,這就必須將 style-loader 替換為 mini-css-extract-plugin

可以使用 webpack-merge 來分割 dev 與 prod build 的 webpack config。

遷移到 Vite

成功將前端分離出來之後,接著嘗試從 webpack4 遷移到 vite。在 config 與插件部分,因為 Vite 開箱即用,比 webpack 要簡單許多。

先把 vite 與 Vue2 相關插件裝上,jsx 插件則看專案有沒有用到。

$ pnpm i -D vite @vitejs/plugin-vue2 @vitejs/plugin-vue2-jsx

加入 npm scripts,webpack 的內容可以先保留,遷移完成再移除。

"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",

"dev:w": "webpack-dev-server",
"build:w": "webpack --mode production",
},

建立 vite config 配置,比起 webpack 相當的精簡。

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue2'
import vueJsx from '@vitejs/plugin-vue2-jsx'
import path from 'node:path'

export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
'@': path.join(__dirname, 'src'),
// ...
},
},
})

然後這些東西可以全砍了。

# webpack
webpack
webpack-dev-server
webpack-cli
webpack.config.js

# webpack loaders
vue-loader
css-loader
// ...

# webpack plugins
mini-css-extract-plugin
html-webpack-plugin
// ...

# babel
@babel/core
@babel/preset-env
// ...

# postcss
postcss
postcss-import
cssnano
// ...

webpack 相關的東西,特別是那一大堆的 loader 與 plugins 都不再需要了。

postcss 在 vite 雖有內建,但 postcss-preset-env 沒內建,要另外裝。

babel 除非有特殊需求,不然在 IE 已經正式走入歷史的現在,for 現代瀏覽器的 vite,babel 已不再是標配。需要編譯 jsx 的話,vite 有專門的 plugin。

如果真有兼容老瀏覽器的需求,可以裝 @vitejs/plugin-legacy ,裡面已包好 babel 配置。

再來就是嘗試啟動的除錯之旅。

vite 雖然在 config 沒有一堆煩人的 loader 與 plugins,但這只是在設定上比較精簡,實際跟 webpack 環境還是有很多需要磨平的地方。

import 需加上 .vue 副檔名

webpack4 環境多數會設定省略 .vue 副檔名。 vite + Vue3 環境則是強烈建議加上副檔名,以便 VScode + Volar 獲取 type 定義。

// 加上 .vue
import App from './App.vue'

可是一個一個去加 .vue 太吐血了,vite 現在也支援 webpack 同款設定,去省略副檔名。

// vite.config.js
resolve: {
extensions: ['.mjs', '.js', '.mts', '.ts', '.vue'], // 省略副檔名
},

sass 的 /deep/ 寫法變更

前面有提過,雖然不是 vite vs webpack 的問題,但還是要注意一下。原本舊的 /deep/ 寫法要改成 :deep

這種寫法 /deep/.my-class 替換時要注意加空格 :deep .my-class。而更新的版本會要求使用 :deep()

雖然這嚴格來說不是 sass 的語法,但它會被 sass 或其他預處理器的版本所影響。

sass v2 棄用顯示數學計算

sass v1.32 以上版本,會出現棄用提示,不再支持直接的數學計算寫法。

// NG
1 / 5

要改成這種 function 調用的寫法。

// OK
calc(1 / 5)
math.div(1, 5)

如果有用 element-ui,它內部 Sass 有用舊的數學寫法,會一直噴警告,只能將 sass 退版到 ~1.32,忽略警告。

在 css import node_modules

webpack 支持使用波浪號 ~ 在 css 導入 node_modeuls。但這個 vite 看不懂,vite 是採用跟 js 同款寫法來處理。

// webpack
@import "~element-ui/packages/theme-chalk/src/index";

// vite
@import "element-ui/packages/theme-chalk/src/index";

懶得手動修改的話,可以透過 alias 設定,讓 vite 辨識波浪號。

resolve: {
alias: [
// 正規判斷 ~ 開頭, 指向 node_modules
{
find: /^~(?!\/)/,
replacement: path.join(__dirname, 'node_modules/'),
},
],
}

jsx 用法變更

webpack 環境下,隨著 babel 等相關插件的新舊版本差異,jsx 的用法略有不同。而 vite 這邊畢竟比較新,可直接在 <script setup> 裡面使用 jsx。

但要注意,vite 中使用 jsx 需要打上 lang 標記作為識別符號。

<script lang="jsx">
// ...
</script>

process.env 不可用

process.env 為 Node.js 語法,在 vite 中不可用,需以 import.meta 替代。

// webpack
process.env.NODE_ENV

// vite
import.meta.env.MODE

vite 不支援 CommonJS 需改為 ESM

vite 使用 ESM 而不是 CommonJS,需將 require / module.exports 改為 import / export。

// NG
const axios = require('axios')
module.exports = { foo: 'bar' }

// OK
import axios from 'axios'
export default { foo: 'bar' }

社群也有人製作 vite 的 CommonJS 插件 vite-plugin-commonjs ,懶得手動改的話可以試試。

另外 webpack 還有 script-loader 提供的特殊語法。雖然我這專案有這行 code,但排查後發現沒有被使用到,我就先跳過了。

// webpack + script-loader
require('script-loader!jsonlint')

目前只知道 script-loader 在做的事,是把目標 js 引入後,直接在 global 執行一次。也就是該 js 的內容會註冊到 window 上可供調用。

我查不到 vite 該如何實現等價操作,但這專案的這段 code 研究了一下,主要是用 codemirror + jsonlint 在瀏覽器上弄一個 JSON 編輯器出來。

網上比較新的相關教學,是使用模塊化版本的 jsonlint-mod 來做,這樣就不需要使用到 script-loader 了。

import jsonlint from 'jsonlint-mod'
window.jsonlint = jsonlint

vite build 需另外設定處理 CommonJS

如果選擇使用 vite-plugin-commonjs ,那在 build 時會碰到問題,因為這插件是 for dev mode 的。

另外,也可能會碰到老套件內部使用 CommonJS,我們無法去改它。只能透過 vite-plugin-commonjs 來處理。

這樣在 build 時,要去設定 rollup 轉換 CommonJS。

// vite.config.js
build: {
commonjsOptions: {
transformMixedEsModules: true, // 轉換兼容 commonjs
},
},

webpack require.context() 不可用

require.context() 是 webpack 提供的特殊語法,可用來獲取資料夾目錄,實現自動化導入。這個 vite 自然是看不懂的。

但 vite 有等價語法,可用 import.env.glob 來改寫。例如要匯入 files 資料夾裡的所有 js:

// webpack
const files = require.context('./files', true, /\.js$/)
const fileObj = files.keys().reduce((obj, path) => {
const file = files(path)
obj[path] = file.default
return obj
}, {})


// vite
const files = import.meta.glob('./files/*.js', { eager: true })
const fileObj = Object.keys(files).reduce((obj, path) => {
const file = files[path]
obj[path] = file.default
return obj
}, {})

要注意回傳的東西不太一樣,require.context() 回傳的是 function,並帶有 props。而 import.meta.glob() 則是回傳一個 object。

vite 與 webpack5 不再提供 path 等 polyfill

path 是 Node.js 提供的模塊,並不是瀏覽器有的東西。

如今 vite 與 webpack5 都不再提供 polyfill,在瀏覽器端執行的 code,不能直接引入使用。

vite 環境下,瀏覽器端的 code 原則上都不該使用 path 這些 Node.js 的功能了。但是老 code 已經這樣寫了,怎麼辦?

可以安裝瀏覽器版本 path-browserify 頂一下,但最好找時間把有用到的地方重寫。安裝之後,利用 alias 設定來映射。

// vite.config.js
resolve: {
alias: {
// remapping to path-browserify
path: 'path-browserify',
},
},

如果老 code 有用到 path.resolve() 會很麻煩,它會在內部以 global 的方式調用 process.cwd()

這雖然也有瀏覽器版本 process

但由於它是在 global 被調用的,沒有使用 import 關鍵字,所以無法設定 alias 來處理,得用比較 cheat 的做法,將其在 html 頭部導入後,掛到 window 上面。

<!-- index.html -->
<script type="module">
import process from 'process'
window.process = process
</script>

處理 css :export

webpack 的 css-loader 有提供一種 :export 語法,讓 js 可以 import 在 css 或 sass 中被定義的變數。

而在 vite 則透過 css-modules 支援此語法,但要將有用到 :export 的檔案更名為 css modules 的格式,添加中間名 xxx.module.css

另外要注意,如果在有使用 :export 的檔案中 import node_modules 的話,vite 會把套件裡面定義的變數也全都導出,嚴重影響編譯速度。

// somthing.scss
$--color-primary: #1890ff;

/* js import 時,vite 會將 element-ui 內的變數也全數導入 */
@import "element-ui/packages/theme-chalk/src/index.scss";

:export {
theme: $--color-primary;
}

這部分要視專案情況改寫,把 import 跟 :export 分離開來。

替代 webpack svg-sprite-loader

svg-sprite-loader 這玩意顧名思義是用精靈圖的概念去一次性導入 svg 檔案。

如果有用到這個,應該會有一段使用 require.context() 批次導入 svg icon 的 code,並依靠該 loader 在導入時自動註冊 svg。

// 自動導入 ./svg 資料夾下的所有 .svg files
const req = require.context('./svg', false, /\.svg$/)
const requireAll = (requireContext) => {
return requireContext.keys().map(requireContext)
}
requireAll(req)

vite 有個等價的插件 vite-plugin-svg-icons,並且會把自動導入部分也處理好,所以上面那段 code 可以直接砍掉,改去 config 設定就好。

// vite.config.js
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

export default defineConfig({
plugins: [
// svg 預加載, 替代 webpack svg-sprite-loader
createSvgIconsPlugin({
// 指定 dir 自動導入
iconDirs: [path.join(__dirname, 'src/icons/svg')],
// svg-sprite-loader 會打上一個供調用的 id
// 這邊設成一樣的讓老 code 能呼叫到
symbolId: 'icon-[name]',
}),
],
})

pnpm ignore missing peer 警告

vite 有很多套件的 core 都內建了,只要安裝相關 plugin 就好,例如要使用 postcss-preset-env 時,並不需要安裝 postcss

但是 pnpm 會偵測到它依賴 postcss,可它在 vite 底下,pnpm 不做深度檢查,所以它會誤判沒有安裝 peer 依賴,跳出 missing peer 警告。

另外像是 ant-design-vue 也有設定依賴 vue-template-compiler ,可是 vite 不需要裝這個,pnpm 也會跳出警告。

這問題可以在 package.json 設定 pnpm ignore missing peer 解決。

// package.json
{
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": ["vue-template-compiler", "postcss"]
}
}
}

build 後 el-table 呈現空白

如果使用 element-ui 與 Vue2.7,可能會碰到 dev 啟動一切正常,但 build 後 el-table 卻 render 空白的情況。

這似乎是 vue2.7 採用新版 vue-template-complier 與 element-ui 內部寫法衝突導致的問題。在 build 時 element-ui 導入了不同的 vue core,錯誤產生了兩個不同的 vue instance,造成 el-table 吃不到專案的 context。

可透過 alias 配置,強制統一 vue 的引入目標。

// webpack
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
},
},

// vite
resolve: {
alias: {
vue: 'vue/dist/vue.esm.js',
},
},

element-ui 自訂 theme 被 umy-ui 搶 css 權重

我這專案同時使用 element-ui 與 umy-ui,都是全域引入該庫的 css。遷移到 vite 後卻發現 element-ui 的 class name 跟 umy-ui 撞名,自定義 theme 的 css 被 umy-ui 給搶權重。

研究半天發現,這兩個套件的 css 引入順序是這樣寫的。

import element-ui css
import custom element-ui theme sass
import umy-ui css

由於 umy-ui 最後才引入,必然它的權重是最強的。但由於 webpack 本身的 bug,錯誤將 Sass 文件最後才引入,所以在 webpack 環境下反而運行正常。

遷移到 vite 之後,只需調整正確的順序即可。

import element-ui css
import umy-ui css
import custom element-ui theme sass // change this

vite 中 template whitespace 間隔消失

這問題蠻瞎的,原本 webpack 環境下,把兩個 html <input> 放一起,渲染結果會有個小小的、類似 margin 效果的間隔。但遷移到 vite 之後卻消失了。

最初以為是 css 跑掉了,查了半天才發現是 template 編譯的問題……

<!-- source -->
<input />
<input />

<!-- webpack 編譯後 -->
<input /> <input />

<!-- vite 編譯後 -->
<input /><input />

Vue 的 template 本身是種模板引擎,跟 pug 那些一樣,會有 white space 的相關設定。

webpack 的 vue-loader 預設是將 line break 轉換成 space。而 vite 的 plugin-vue2 則會完全 minify。

可以透過設定 vue template 的 whitespace 還原。

// vite.config.js
plugins: [
vue({
template: {
compilerOptions: {
// 使 template 編譯保留空格
whitespace: 'preserve',
},
},
}),
],

ES6+ 語法出現 VScode ts 報錯

專案環境改變後,莫名其妙這一些 ES6+ 語法,在 VScode 中出現了紅線。

Object.entries()
// Property 'entries' does not exist on type 'ObjectConstructor'

async function foo() {}
// An async function or method in ES5/ES3 requires the 'Promise' constructor

排查後發現,是因為 VScode 將 ES+6 的語法拆成了不同的包,預設是不使用。需要在 jsconfig 或 tsconfig 添加 lib ESNext 設定。

// jsconfig.json
{
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ESNext"]
}
}

--

--

Lastor
Code 隨筆放置場

Web Frontend / 3D Modeling / Game and Animation. 設計本科生,前遊戲業 3D Artist,專擅日本動畫與遊戲相關領域。現在轉職為前端工程師,以專業遊戲美術的角度涉足 Web 前端開發。