忽略編譯 精讀《如何編譯前端專案與元件》

2021-10-25 12:26:16 字數 4209 閱讀 3818

說到前端編譯方案,也就是如何打包專案,如何編譯元件,可選方案有很多,比如:

如果你業務比較複雜,需要使用 webpack 做深度定製,那麼常見組合是:專案 - webpack,元件 - gulp。

但專案與元件的編譯存在異同點,不同構建工具支援的生態也存在異同點。

專案構建的目的主要在於發布 cdn,所以大家一般不在乎構建指令碼的通用性。換句話說,無論專案使用了怎樣的構建方式,怎樣理解import語句,甚至寫出require.context等自定義語法,只要最終編譯出符合瀏覽器規範的**(考慮到相容性)就足夠。

元件構建的目的主要在於發布 npm,除了 esnext 規範會使用 babel 編譯成 es3,大部分**寫的很收斂,甚至對 sass 的使用都要與 typescript 外掛程式一起組合成複雜的 gulp task。

所以往往大家會對專案採取複雜的構建約束策略,而對元件的編譯採取相對簡單的辦法,確保發布**的通用性。

所以在大部分專案使用 webpack 支援 worker-loader 時,編寫元件時發現這段**不靈了。或者至少你得付出一些代價,因為元件的除錯依然可以利用 webpack-dev-server,這時可以加上 worker-loader,但由於 gulp 沒有靠譜的 worker 外掛程式,你的元件可能需要將 worker 引用部分原樣輸出,希望由引用它的專案做掉對 worker-loader 的支援。

其實這種心態是很危險的,不僅導致了元件不通用,甚至引發了各構建工具的 tree shaking 優化。原因就是構建元件的**太原始,冗餘的**沒有刪除,甚至直接引用的 sass **仍然保留,更危險的是帶上了一些特殊 webpack loader 才支援的語法。

之所以說 antd 是乙個擁有優秀基因的前端元件庫,是因為他遵循了前端元件最基本的**素養:

編譯後的**全部符合基本 js 規範,換個角度來說,使用 webpack 內建基本 js loader 就能完全解析。

將 css **抽離出來,這樣不會強制專案對 node_modules 的**應用 css-loader。

所以乙個靠譜的元件庫的產出檔案,應該符合基本 es 模組化規範,且不包括任何特殊語法。

但是這引發了乙個新的問題:元件開發體驗比專案差很多。

比如元件想使用雪碧圖自動優化、想使用 worker-loader 方便快捷的呼叫多執行緒,想用自己的 css modules,甚至想把專案裡一堆 postcss 快捷語法搬過來時怎麼辦?難道元件開發就不能獲得與專案開發一樣的體驗嗎?

要解決這個問題,筆者介紹一種基於 webpack 的通用構建方案,讓本地除錯、cdn 打包、es6 -> es3 轉換 都使用統一套配置**,同一套 loader。

核心思想只有一句話:利用 webpack-node-externals 忽略 webpack 對指向 node_modules 的 require 或 import 語句:

進行專案/元件除錯時,開啟development模式。

進行專案編譯時,開啟production模式。

進行元件編譯時,開啟production模式,且利用 webpack-node-externals 外掛程式忽略 node_modules。

可以想像,根據第三條,如果所有元件都按照這個模式輸出**,那麼 webpack 對 node_modules 編譯時,只需要將所有require**進行合併,不需要執行任何 loader,也不需要壓縮,不需要 treeshaking,因為這些在元件**編譯時全部已經做好了,這種構建效率幾乎達到最大。

我們拿支援typescriptsasscss-modulesworker-loader的場景作為案例。

我們建立三個檔案entry.tsxentry.worker.tsentry.scss

entry.scss:

.container 

.primary

}

entry.worker.ts:

import hello from "hello";

const ctx: worker = self as any;

ctx.onmessage = event => ;

export default null as any;

entry.tsx:

import * as react from "react";

import styles from "./entry.scss";

import * as myworker from "./parser.worker";

const worker = new myworker();

export default () => (

click me.

);

在上面三個檔案中,我們分別利用了 typescript 編譯、scss 編譯、css-modules 解析、worker-loader 解析(利用 webpack 自動生成字串**並利用 blob url 方式載入,這樣就不需要建立新檔案也可以用 worker 了,也不會存在跨域問題)。

為了支援這幾個特性對如上**做除錯、專案發布、元件發布,我們分別看下這三個場景該如何配置編譯指令碼。

本地除錯是不用區分元件與專案的。因為無論何種情況,都需要進行基本的專案編譯,載入所有自定義 loader 並打成乙個 bundle 包。

此時我們只要維護乙份webpack配置即可:

const webpackconfig = 

},include: path.join(projectrootpath, "src")},}

}]]}

],"ts-loader"

],include: path.join(projectrootpath, "src")

},],

"sass-loader"

],include: path.join(projectrootpath, "src")}]

}};export default webpackconfig;

利用這個配置加上webpack-dev-server即可完成元件與專案的本地除錯。

專案發布時,需要將所有**打入到乙個 bundle 包,此時只需使用webpack-cli即可,對配置做如下修改:

export default ;
元件發布時,依然使用webpack-cli構建,但利用webpack-node-externals忽略對node_modules的解析。

import * as nodeexternals from "webpack-node-externals";

export default ;

此時編譯的元件**,包含了 typescript 編譯、scss 編譯、css-modules 解析、worker-loader 解析,但所有node_modules**都保持原樣,比如下面的**:

做了**去重、按需載入、打包、壓縮,但因為保持了require原樣,因此大小只有原始碼體積。

同時上述三個場景都在復用 webpack 一套**的基礎上,利用了 webpack 的生態,因此維護性和拓展性都很強。後續再加入新功能,再也不需要到處找babelgulp的外掛程式了!

本文從webpack為切入點,但其實還可以從parcelgulp為切入點,實現前端專案、元件構建體系的統一。

不過從可定製性來看,webpack外掛程式生態更完善,所以筆者選擇了webpack

如果你想參與討論,這裡,每週都有新的主題,週末或周一發布。前端精讀 - 幫你篩選靠譜的內容。

前端學習十一(vuex 專案編譯)

一 vuex 個人理解是多個vue元件資料共享時使用 vuex文件 1 環境準備 1 安裝依賴 npm install vuex s e 2 安裝外掛程式 vue ui中安裝外掛程式vuex 會新建乙個store的資料夾,且main.js也會自動匯入store 2 vuex的核心概念 state g...

vuex 編譯專案 俺咋能看懂公司前端專案?

我是一名剛步入社會的有志青年開發者。在校學了三年的後端開發,沒想到剛步入公司幹起了前端工作,華麗的轉變讓我有點猝不及防,誰讓我辣麼優秀!趁著頭髮茂密,讓我們步入正題!很有幸進入公司就參與了專案的開發,專案的前端是採用的vue和element框架,我剛拿到公司封裝之後的vue的腳手架翻了翻,瞬間感覺對...

如何通過命令列 msbuild 編譯專案

本文告訴大家如何通過 msbuild 編譯乙個專案,通過命令列編譯可以輸出更多的編譯資訊,可以用來除錯自己寫的編譯相關方法,可以看到是哪個檔案編譯失敗 在開始選單可以找到 visualstudio 的安裝資料夾,基本上開發者命令列的英文名叫 developer command prompt 中文名是...