遷移
絕大部分來說,Parcel 2 的運作方式與 Parcel 1 十分類似,但升級時有幾件事需要變更。
入門
#讓我們逐步了解從 Parcel 1 升級到 Parcel 2 的幾個基本步驟。
套件名稱
#從 Parcel 1 升級到 Parcel 2 時,首先要注意的是 npm 套件名稱已從 parcel-bundler
變更為 parcel
。您需要相應地更新 package.json
中的相依性。
{
"devDependencies": {
"parcel-bundler": "^1.12.5"
}
}
{
"devDependencies": {
"parcel": "^2.0.0"
}
}
您也可以使用套件管理員來執行此動作,例如 npm
或 yarn
。
yarn remove parcel-bundler
yarn add parcel --dev
快取位置
#Parcel 快取的預設位置也已從 .cache
變更為 .parcel-cache
。您需要修改 .gitignore
或類似設定來因應此變更
.cache
.parcel-cache
程式碼變更
#<script type="module">
#在 Parcel 1 中,從 HTML 檔案中的 <script>
標籤引用的 JavaScript 檔案被視為模組,支援 ES 模組和 CommonJS 語法來匯入和匯出值。然而,這與瀏覽器的實際運作方式不符,其中「傳統腳本」不支援匯入和匯出,且頂層變數被視為全域變數。
Parcel 2 與瀏覽器行為相符:傳統 <script>
標籤不支援匯入或匯出。請使用 <script type="module">
元素來引發模組。這也會自動產生 nomodule
版本,適用於較舊的瀏覽器,具體取決於您的 browserslist
。請參閱 差異化打包 以取得詳細資訊。
<!doctype html>
<html>
<head>
<script src="app.js"></script>
</head>
</html>
<!doctype html>
<html>
<head>
<script type="module" src="app.js"></script>
</head>
</html>
注意:新增 type="module"
屬性也會影響腳本的載入行為。傳統腳本是「阻擋渲染」,表示在腳本執行完成之前,不會解析 HTML 文件的其餘部分。模組腳本不會阻擋渲染,而且會延遲執行,直到 HTML 完全解析完畢。Parcel 會自動插入 defer
屬性,以符合舊瀏覽器和開發模式中的此行為。這表示 document.write
等功能無法在模組腳本中運作。如果您依賴這些功能,請改用現代 API 或繼續使用傳統腳本處理應用程式的那個部分。請參閱 MDN 上的文件,以進一步了解模組和傳統腳本之間的差異。
請參閱 傳統腳本,以進一步了解傳統腳本與模組腳本的差異。
從 JavaScript 匯入非程式碼資源
#在 Parcel 1 中,匯入任何非 JavaScript 檔案(例如圖片或影片)都會產生一個 URL。在 Parcel 2 中,這仍然適用於已知檔案類型(例如圖片),但沒有預設支援的其他檔案類型需要變更程式碼。
在 JavaScript 中參照 URL 的建議做法是使用 URL 建構函式。不過,您也可以選擇在 import
陳述式中,使用 url:
為相依項規格加上字首。
import downloadUrl from "./download.zip";
document.body.innerHTML = `<a href="${downloadUrl}">Download</a>`;
const downloadUrl = new URL('download.zip', import.meta.url);
document.body.innerHTML = `<a href="${downloadUrl}">Download</a>`;
或者,您可以使用自訂的 .parcelrc
選擇舊行為。對您需要的副檔名使用 @parcel/transformer-raw
外掛程式和萬用字元。
yarn add @parcel/config-default @parcel/transformer-raw --dev
{
"extends": "@parcel/config-default",
"transformers": {
"*.{zip,tgz}": ["@parcel/transformer-raw"]
}
}
轉譯
#Parcel 1 自動將您的 JavaScript 轉譯為支援預設瀏覽器。Parcel 2 預設不再進行任何轉譯。這表示如果您在原始程式碼中使用現代 JavaScript 語法,Parcel 會輸出該語法。若要啟用轉譯,請將 package.json 中的 browserslist
欄位設定為定義您支援的瀏覽器目標。
{
"name": "my-project",
"browserslist": "> 0.5%, last 2 versions, not dead",
"scripts": {
"start": "parcel index.html",
"build": "parcel build index.html"
},
"devDependencies": {
"parcel": "latest"
}
}
Babel
#與 Parcel 1 相同,Parcel 2 會自動偵測 .babelrc
和其他 Babel 設定檔。但是,如果您只使用 @babel/preset-env
、@babel/preset-typescript
和 @babel/preset-react
,則可能不再需要 Babel。Parcel 自動支援所有這些功能,無需 Babel 設定檔,而且 Parcel 的預設轉譯器比 Babel 快得多。
如果您只使用上述預設值,您可以完全刪除 Babel 設定檔。這將改用 Parcel 的預設轉譯器,這應該會大幅提升您的建置效能。請務必在 package.json
中設定 browserslist
,以符合 @babel/preset-env
先前使用的目標。
如果您在 Babel 設定檔中有自訂預設值或外掛程式,您可以保留這些設定檔,但移除上述列出的預設值。這也應該會提升效能(儘管幅度較小)。請參閱 JavaScript 文件中的 Babel,以取得更多詳細資訊。
在此範例中,.babelrc
僅包含 @babel/preset-env
和 @babel/preset-react
,因此可以刪除,並以 package.json
中的 browserslist
金鑰取代。
{
"presets": [
["@babel/preset-env", {
"targets": "> 0.25%, not dead"
}],
"@babel/preset-react"
]
}
{
"browserslist": "> 0.25%, not dead"
}
Typescript
#Parcel 1 使用 tsc
(官方 TypeScript 編譯器)轉譯 TypeScript。Parcel 2 現在改用 SWC,這大幅提升了轉譯效能。
不過,預設的轉譯器對 tsconfig.json
的支援有限。如果你使用自訂編譯器選項(超出 JSX 相關選項和 experimentalDecorators
),你可以使用 @parcel/transformer-typescript-tsc
來取代 Parcel 預設的 TypeScript 轉換器。為此,請安裝預設設定檔和 TSC 外掛程式,並在專案根目錄建立一個 .parcelrc
檔案。
yarn add @parcel/config-default @parcel/transformer-typescript-tsc --dev
{
"extends": "@parcel/config-default",
"transformers": {
"*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"]
}
}
請參閱 TypeScript 文件,以取得更多關於使用 Parcel 搭配 TypeScript 的資訊。
Flow
#就像 Parcel 1 一樣,當安裝 flow-bin
時,Parcel 2 會自動支援 Flow。這目前是使用 @babel/preset-flow
來實作。如果你有一個僅包含該預設設定檔的 Babel 設定檔,則可以按照 上方所述將其移除。
與 Parcel 1 不同,你的 Babel 設定檔會覆寫 Parcel 2 中的預設設定檔,而不是與其合併。如果你有 Flow 以外的自訂 Babel 外掛程式,則需要另外加入 @babel/preset-flow
。
匯入 GraphQL
#當匯入 GraphQL 檔案 (.gql
) 時,匯入仍然會解析/內嵌 (使用 graphql-import-macro
),但現在你會取得已處理的 GraphQL 查詢,而不是 Apollo AST。
import fetchDataQuery from "./fetchData.gql"; // fetchDataQuery is the parsed AST
const DataComponent = () => {
const { data } = useQuery(fetchDataQuery, {
fetchPolicy: "cache-and-network",
});
// ...
};
import gql from "graphql-tag";
import fetchDataQuery from "./fetchData.gql"; // fetchDataQuery is a string
// Convert to the Apollo Specific Query AST
const parsedFetchDataQuery = gql(fetchDataQuery);
const DataComponent = () => {
const { data } = useQuery(parsedFetchDataQuery, {
fetchPolicy: "cache-and-network",
});
// ...
};
有了 Parcel 2 的新外掛程式架構,建立一個外掛程式來在建置時將字串剖析成 AST (就像 Parcel 1 所做的一樣) 非常容易。請參閱 轉換器 文件以取得詳細資訊。
package.json#main
#許多 package.json
檔案 (例如由 npm init
產生的檔案) 都包含一個 main
欄位,而大多數工具 (對於非函式庫專案) 都會忽略此欄位。不過,當看到 main
欄位時,Parcel 會推斷你的專案是一個函式庫,並將其用作輸出路徑。對於大多數網路應用程式,應該移除這行。
{
"main": "index.js",
"scripts": {
"start": "parcel index.html",
"build": "parcel build index.html"
}
}
{
"scripts": {
"start": "parcel index.html",
"build": "parcel build index.html"
}
}
如果你確實需要保留 main
欄位,而且希望 Parcel 忽略它,則可以在 package.json
中加入 "targets": { "main": false }
。請參閱 函式庫目標 以取得詳細資訊。
CLI
#--target
#在 Parcel 1 中,--target
CLI 選項控制您的程式碼編譯的環境。在 Parcel 2 中,這改為在 package.json
中設定。例如,設定 engines
欄位以包含 node
或 electron
金鑰,將相應地變更目標。
parcel build index.js --target node
{
"engines": {
"node": "10"
}
}
您也可以在 Parcel 2 中同時建置多個目標。有關詳細資訊,請參閱 目標。
--experimental-scope-hoisting
#Parcel 2 預設啟用範圍提升。若要停用,請新增 --no-scope-hoist
。
parcel build index.js --experimental-scope-hoisting
parcel build index.js
parcel build index.js
parcel build index.js --no-scope-hoist
--bundle-node-modules
#若要將套件從 node_modules
綑綁到目標 Node.js 時,您現在應該在目標設定中指定。
parcel build index.js --target node --bundle-node-modules
{
"targets": {
"default": {
"includeNodeModules": true
}
},
"engines": {
"node": "10"
}
}
此選項比 CLI 參數更靈活。例如,您也可以選擇性地包含套件。有關詳細資訊,請參閱目標文件中的 includeNodeModules。
--out-dir
#--out-dir
CLI 選項已重新命名為 --dist-dir
,以符合 package.json
中的 distDir
選項。有關詳細資訊,請參閱 目標。
parcel build index.html --out-dir www
parcel build index.html --dist-dir www
--out-file
#--out-file
CLI 選項已移除,路徑應改為在 package.json
中指定。有關詳細資訊,請參閱 多個目標 和 函式庫目標。
parcel build index.js --out-file lib.js
{
"name": "my-library",
"version": "1.0.0",
"main": "lib.js"
}
--log-level
#記錄層級現在有名稱,而不是數字 (none
、error
、warn
、info
、verbose
)。
parcel build index.js --log-level 1
parcel build index.js --log-level error
--global
#此選項已移除,暫時沒有替代方案。
parcel build index.js --global mylib
--no-minify
#此選項已重新命名為 --no-optimize
。
parcel build index.js --no-minify
parcel build index.js --no-optimize
API
#使用 Parcel 2 編寫程式時,可以使用 @parcel/core
套件,而不是 parcel-bundler
。API 已大幅變更。有關詳細資訊,請參閱 Parcel API。
掛入套件事件
#Parcel 1 讓您可以使用 API 掛入並聆聽事件,例如 buildEnd
或 buildError
。API 已變更,但您仍然可以聆聽事件,如下所示
import Bundler from "parcel-bundler"
const bundler = new Bundler({ /* ... */ })
bundler.bundle()
bundler.on("buildEnd", () => { /* ... */ })
bundler.on("buildError", (error) => { /* ... */ })
import Parcel from "@parcel/core"
const bundler = new Parcel({ /* ... */ })
bundler.watch((err, buildEvent) => {
if (buildEvent.type === "buildSuccess") { /* ... */ }
if (buildEvent.type === "buildFailure") { /* ... */ }
})
外掛程式
#外掛系統在 Parcel 2 中已完全更改。Parcel 1 外掛與 Parcel 2 不相容。有關 Parcel 2 外掛 API 的詳細資訊,請參閱 外掛系統。
使用外掛
#在 Parcel 1 中,將外掛安裝到專案中並將它們列在 package.json
相依性中即可自動啟用它們。在 Parcel 2 中,外掛會在 .parcelrc
中設定。有關詳細資訊,請參閱 Parcel 設定。