1. 前言
大家好,我是若川,歡迎關注我的公眾號:若川視野。從 2021 年 8 月起,我持續組織了好幾年的每週大家一起學習 200 行左右的源碼共讀活動,感興趣的可以點此掃碼加我微信 ruochuan02 參與。另外,想學源碼,極力推薦關注我寫的專欄《學習源碼整體架構系列》,目前是掘金關注人數(6k+人)第一的專欄,寫有幾十篇源碼文章。
截至目前(2024-11-07),目前最新是 4.0.7,官方4.0正式版本的介紹文章暫未發佈。官方之前發過Taro 4.0 Beta 發佈:支持開發鴻蒙應用、小程序編譯模式、Vite 編譯等。
計劃寫一個 Taro 源碼揭秘系列,博客地址:https://ruochuan12.github.io/taro 可以加入書籤,持續關注若川。
- [x] 1. 揭開整個架構的入口 CLI => taro init 初始化項目的秘密
- [x] 2. 揭開整個架構的插件系統的秘密
- [x] 3. 每次創建新的 taro 項目(taro init)的背後原理是什麼
- [x] 4. 每次 npm run dev:weapp 開發小程序,build 編譯打包是如何實現的?
- [x] 5. 高手都在用的發佈訂閲機制 Events 在 Taro 中是如何實現的?
- [x] 6. 為什麼通過 Taro.xxx 能調用各個小程序平台的 API,如何設計實現的?
- [x] 7. Taro.request 和請求響應攔截器是如何實現的
- [x] 8. Taro 是如何使用 webpack 打包構建小程序的?
- [x] 9. Taro 是如何生成 webpack 配置進行構建小程序的?
- [x] 10. Taro 到底是怎樣轉換成小程序文件的?
- [ ] 等等
前面 4 篇文章都是講述編譯相關的,CLI、插件機制、初始化項目、編譯構建流程。
第 5-7 篇講述的是運行時相關的 Events、API、request 等。
第 8 篇接着繼續追隨第4篇 npm run dev:weapp 的腳步,繼續分析 @tarojs/webpack5-runner,Taro 是如何使用 webpack 打包構建小程序的?
關於克隆項目、環境準備、如何調試代碼等,參考第一篇文章-準備工作、調試。後續文章基本不再過多贅述。
學完本文,你將學到:
1. 如何輸出項目的 webpack 配置,原理是什麼
2. Taro 生成的 webpack 配置解讀
等等
2. webpack 打包構建
4. 每次 npm run dev:weapp 開發小程序,build 編譯打包是如何實現的?
在第4篇文章末尾,我們可以回顧下,如何獲取 webpack 配置和 執行 webpack() 構建的。
// packages/taro-webpack5-runner/src/index.mini.ts
import webpack from 'webpack'
// 省略若干代碼
export default async function build (appPath: string, rawConfig: IMiniBuildConfig): Promise<Stats | void> {
const combination = new MiniCombination(appPath, rawConfig)
await combination.make()
// 省略若干代碼
const webpackConfig = combination.chain.toConfig()
const config = combination.config
return new Promise<Stats | void>((resolve, reject) => {
if (config.withoutBuild) return
const compiler = webpack(webpackConfig)
// 省略若干代碼...
if (config.isWatch) {
compiler.watch({
aggregateTimeout: 300,
poll: undefined
}, callback)
} else {
compiler.run((err: Error, stats: Stats) => {
compiler.close(err2 => callback(err || err2, stats))
})
}
})
}
// 重點就以下這幾句
// 生成獲取 webpack 配置,執行 webpack(webpackConfig)
const combination = new MiniCombination(appPath, rawConfig)
await combination.make()
const webpackConfig = combination.chain.toConfig()
const compiler = webpack(webpackConfig)
我們可以調試代碼,從這裏輸出 webpackConfig。不過我們使用另外一種,腳手架提供的 inspect。
3. 輸出打包編譯 taro 的 webpack 配置
我們先初始化一個 Taro 項目。
npx @tarojs/cli@latest init taro4-debug
我們選擇 react、ts、pnpm、webpack5、CLI 內置默認模板 等配置生成的項目,如下圖所示:
cd taro4-debug
npx taro -h
如下圖所示:
npx taro inspect -h
如下圖所示:
我們可以知道,-t 指定 weapp -o 指定路徑(文件名)
# 把 taro 編譯微信小程序的 webpack 配置輸出到了 webpack.config.js 文件
npx taro inspect -t weapp -o webpack.config.js
執行上面腳本後,我們就把 taro 編譯微信小程序的 webpack 配置輸出到了 webpack.config.js 文件。我們在開頭追加 export default 方便查看整個文件。如下圖所示:
輸出的 webpack 配置文件,有足足 2.4w 行,想想就害怕,不過放心,我們肯定要刪減的,只看重點。
我們先來看 inspect 插件源碼,分析其原理。
3.1 inspect 插件
我們可以從第二篇文章,2. 揭開整個架構的插件系統的秘密
得知,找到對應插件的源碼路徑 packages/taro-cli/src/presets/commands/inspect.ts。
// packages/taro-cli/src/presets/commands/inspect.ts
export default (ctx: IPluginContext) => {
ctx.registerCommand({
name: 'inspect',
optionsMap: {
'-t, --type [typeName]': 'Build type, weapp/swan/alipay/tt/h5/quickapp/rn/qq/jd',
'-o, --output [outputPath]': 'output config to outputPath'
},
synopsisList: [
'taro inspect --type weapp',
'taro inspect --type weapp --output inspect.config.js',
'taro inspect --type weapp plugins',
'taro inspect --type weapp module.rules.0'
],
async fn ({ _, options }) {
// 省略,拆分到下方講述
}
})
}
// 省略代碼
3.2 fn 函數
async fn ({ _, options }) {
const { fs, chalk } = ctx.helper
const platform = options.type || options.t
// 省略若干代碼
const isProduction = process.env.NODE_ENV === 'production'
const outputPath = options.output || options.o
const mode = outputPath ? 'output' : 'console'
const extractPath = _[1]
await ctx.applyPlugins({
name: platform,
opts: {
config: {
...config,
isWatch: !isProduction,
mode: isProduction ? 'production' : 'development',
async modifyWebpackChain (chain, webpack, data) {
await ctx.applyPlugins({
name: hooks.MODIFY_WEBPACK_CHAIN,
initialVal: chain,
opts: {
chain,
webpack,
data
}
})
},
onWebpackChainReady (chain) {
const webpackConfig = chain.toConfig()
const { toString } = chain.constructor
const config = extractConfig(webpackConfig, extractPath)
const res = toString(config)
if (mode === 'console') {
const highlight = require('cli-highlight').default
console.info(highlight(res, { language: 'js' }))
} else if (mode === 'output' && outputPath) {
fs.writeFileSync(outputPath, res)
}
process.exit(0)
}
}
}
})
}
ctx.applyPlugins 觸發平台插件 weapp,傳入 config ,傳入兩個鈎子函數 modifyWebpackChain、onWebpackChainReady。
在 taro 源碼中,搜索 onWebpackChainReady,可以搜索到調用的地方。
function onWebpackChainReady(chain){
const webpackConfig = chain.toConfig()
const { toString } = chain.constructor
const config = extractConfig(webpackConfig, extractPath)
const res = toString(config)
// 根據傳入的模式參數,輸出到控制枱或者寫入文件
}
// 調用
onWebpackChainReady(chain)
其中 chain 是 webpack-chain 的實例對象。
const Chain = require('webpack-chain');
根據上述用法,可以推斷 webpack-chain 簡版代碼,有 class Chain 類,toString 靜態方法和 toConfig 實例對象方法。可以簡單實現 Chain 類如下所示。
class Chain{
constructor(){}
static toString(){
console.log('string');
return JSON.stringify({});
}
toConfig(){
console.log('toConfig');
return {};
}
}
感興趣的小夥伴可以查看其源碼 webpack-chain
4. webpack 配置
webpack 中文文檔、webpack 英文文檔
按 webpack 文檔配置順序,整理 taro 的 webpack 配置對象屬性的順序如下。
export default {
entry: {
app: [
'/Users/ruochuan/git-source/github/taro4-debug/src/app.ts'
]
},
mode: 'production',
output: {},
module: {
},
resolve: {},
resolveLoader: {},
optimization: {},
plugins: [],
devtool: false,
target: [
'web',
'es5'
],
watchOptions: {
aggregateTimeout: 200
},
performance: {
maxEntrypointSize: 2000000
},
}
接下來,我們逐一解釋這些配置。
4.1 entry 入口
入口對象是用於 webpack 查找開始構建 bundle 的地方。上下文是入口文件所處的目錄的絕對路徑的字符串。
export default {
// 入口文件
entry: {
app: [
'/Users/ruochuan/git-source/github/taro4-debug/src/app.ts'
]
}
}
打包後的入口 app.js,如圖所示:
4.2 mode 模式
提供 mode 配置選項,告知 webpack 使用相應模式的內置優化。
string = 'production': 'none' | 'development' | 'production'
export default {
mode: 'production',
}
4.3 output 輸出
output 位於對象最頂級鍵(key),包括了一組選項,指示 webpack 如何去輸出、以及在哪裏輸出你的「bundle、asset 和其他你所打包或使用 webpack 載入的任何內容」。
export default {
output: {
chunkLoadingGlobal: 'webpackJsonp',
path: '/Users/ruochuan/git-source/github/taro4-debug/dist',
publicPath: '/',
filename: '[name].js',
chunkFilename: '[name].js',
globalObject: 'wx',
enabledLibraryTypes: [],
devtoolModuleFilenameTemplate: function () { /* omitted long function */ }
},
}
4.4 module 模塊
這些選項決定了如何處理項目中的不同類型的模塊。
export default {
// 代碼有刪減
module: {
rules: [
/* config.module.rule('sass') */
{
test: /\.sass$/,
oneOf: [
/* config.module.rule('sass').oneOf('0') */
// 省略
]
},
/* config.module.rule('scss') */
{
test: /\.scss$/,
},
/* config.module.rule('less') */
{
test: /\.less$/,
},
/* config.module.rule('stylus') */
{
test: /\.styl(us)?$/,
},
/* config.module.rule('normalCss') */
{
test: /\.(css|qss|jxss|wxss|acss|ttss)(\?.*)?$/,
},
// 還有其他配置,拆分到下文
]
},
}
針對 .sass、.scss、.less、.stylus 文件採用對應的 loader 的處理。
和 normalCss (css|qss|jxss|wxss|acss|ttss)各平台的小程序自身的 css 文件的處理。
4.4.1 config.module.rule('script')
/* config.module.rule('script') */
{
test: /\.m?[tj]sx?$/i,
include: [
'/Users/ruochuan/git-source/github/taro4-debug/src',
filename => /(?<=node_modules[\\/]).*taro/.test(filename)
],
use: [
/* config.module.rule('script').use('babelLoader') */
{
loader: '/Users/ruochuan/git-source/github/taro4-debug/node_modules/.pnpm/babel-loader@8.2.1_@babel+core@7.26.0_webpack@5.91.0_@swc+core@1.3.96_/node_modules/babel-loader/lib/index.js',
options: {
compact: false
}
}
]
},
針對 js 的採用 babel-loader 處理。
4.4.2 config.module.rule('template')
/* config.module.rule('template') */
{
test: /\.(wxml|axml|ttml|qml|swan|jxml)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: function () { /* omitted long function */ }
},
use: [
/* config.module.rule('template').use('0') */
{
loader: '/Users/ruochuan/git-source/github/taro4-debug/node_modules/.pnpm/@tarojs+webpack5-runner@4.0.7_@babel+core@7.26.0_@swc+core@1.3.96_@tarojs+runtime@4.0.7_less@_emqo6xqihzcps7l7vcv6fz65aa/node_modules/@tarojs/webpack5-runner/dist/loaders/miniTemplateLoader.js',
options: {
buildAdapter: 'weapp'
}
}
]
},
針對各個平台的小程序模板,採用自定義的 miniTemplateLoader 處理。
對應的源碼路徑是 @tarojs/webpack5-runner/dist/loaders/miniTemplateLoader.js
4.4.3 config.module.rule('xscript')
/* config.module.rule('xscript') */
{
test: /\.wxs$/,
type: 'asset/resource',
generator: {
filename: function () { /* omitted long function */ }
},
use: [
/* config.module.rule('xscript').use('0') */
{
loader: '/Users/ruochuan/git-source/github/taro4-debug/node_modules/.pnpm/@tarojs+webpack5-runner@4.0.7_@babel+core@7.26.0_@swc+core@1.3.96_@tarojs+runtime@4.0.7_less@_emqo6xqihzcps7l7vcv6fz65aa/node_modules/@tarojs/webpack5-runner/dist/loaders/miniXScriptLoader.js'
}
]
},
針對 wxs 文件,採用自定義的 miniXScriptLoader 處理。
對應的源碼路徑是 @tarojs/webpack5-runner/dist/loaders/miniXScriptLoader.js。
4.4.4 config.module.rule('media')
/* config.module.rule('media') */
{
test: /\.(mp4|webm|ogg|mp3|m4a|wav|flac|aac)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10240
}
},
generator: {
emit: undefined,
outputPath: undefined,
publicPath: undefined,
filename: function () { /* omitted long function */ }
}
},
對於視頻文件,採用 資源 type: 'asset' 處理。
4.4.5 config.module.rule('font')
/* config.module.rule('font') */
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
type: 'asset',
// 省略
},
4.4.6 config.module.rule('image')
/* config.module.rule('image') */
{
test: /\.(png|jpe?g|gif|bpm|svg|webp)(\?.*)?$/,
type: 'asset',
// 省略
}
4.5 resolve 解析
這些選項能設置模塊如何被解析。webpack 提供合理的默認值,但是還是可能會修改一些解析的細節。關於 resolver 具體如何工作的更多解釋説明,請查看模塊解析。
export default {
resolve: {
symlinks: true,
fallback: {
fs: false,
path: false
},
alias: {
'regenerator-runtime': '/Users/ruochuan/git-source/github/taro4-debug/node_modules/.pnpm/regenerator-runtime@0.11.1/node_modules/regenerator-runtime/runtime-module.js',
'@tarojs/runtime': '/Users/ruochuan/git-source/github/taro4-debug/node_modules/@tarojs/runtime/dist/index.js',
'@tarojs/shared': '/Users/ruochuan/git-source/github/taro4-debug/node_modules/@tarojs/shared/dist/index.js',
'@tarojs/components$': '@tarojs/plugin-platform-weapp/dist/components-react',
'react-dom$': '@tarojs/react',
'react-dom/client$': '@tarojs/react'
},
extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.vue'],
mainFields: ['browser', 'module', 'jsnext:main', 'main'],
plugins: [
/* config.resolve.plugin('MultiPlatformPlugin') */
new MultiPlatformPlugin(
'described-resolve',
'resolve',
{
chain: {
// 省略
}
}
),
/* config.resolve.plugin('tsconfig-paths') */
new TsconfigPathsPlugin()
]
},
resolveLoader: {
modules: [
'node_modules'
]
},
}
symlinks
是否將符號鏈接(symlink)解析到它們的符號鏈接位置(symlink location)。
alias
創建 import 或 require 的別名,來確保模塊引入變得更簡單。resolvealias
平時引入的是組件 @tarojs/components$ 最終對應平台的 @tarojs/plugin-platform-weapp/dist/components-react
react-dom$ 對應 @tarojs/react。
extensions
嘗試按順序解析這些後綴名。如果有多個文件有相同的名字,但後綴名不同,webpack 會解析列在數組首位的後綴的文件 並跳過其餘的後綴。
mainFields
當從 npm 包中導入模塊時(例如,import * as D3 from 'd3'),此選項將決定在 package.json 中使用哪個字段導入模塊。根據 webpack 配置中指定的 target 不同,默認值也會有所不同。
plugins
應該使用的額外的解析插件列表。
MultiPlatformPlugin
此 enhance-resolve 插件用於根據當前編譯的平台,解析多端文件的後綴。
有些場景,單純的根據平台變量 process.env.TARO_ENV 在一個文件裏寫判斷,相對麻煩。這時就可以直接拆分寫多個文件。
src/index.[js|ts|jsx|tsx]
比如 微信小程序端 src/index.weapp.[js|ts|jsx|tsx]
H5 端 src/index.h5.[js|ts|jsx|tsx],這樣就會根據平台直接讀取對應文件。
TsconfigPathsPlugin
tsconfig-paths-webpack-plugin
是一個 webpack 插件,它通過解析 TypeScript 導入路徑來幫助提高 TypeScript 構建的性能。
當您導入 TypeScript 模塊時,webpack 需要將導入路徑解析為相應的 TypeScript 文件。默認情況下,webpack 通過在“node_modules”目錄中搜索 TypeScript 文件來執行此操作。但是,這可能效率低下,尤其是當您的項目有很多依賴項時。
tsconfig-paths-webpack-plugin 提供了一種更高效的方法來解析 TypeScript 導入路徑。它通過讀取項目的 tsconfig.json 文件並生成一組規則來實現此目的,webpack 可以使用這些規則來解析導入路徑。這意味着即使您的項目有很多依賴項,webpack 也可以快速輕鬆地解析導入路徑。
4.6 optimization 優化
從 webpack 4 開始,會根據你選擇的 mode 來執行不同的優化, 不過所有的優化還是可以手動配置和重寫。
export default {
optimization: {
sideEffects: true,
minimize: true,
usedExports: true,
runtimeChunk: {
name: 'runtime'
},
splitChunks: {
// 省略,拆開到下方
},
minimizer: [
// 省略,拆開到下方
]
},
}
4.6.1 optimization.splitChunks
對於動態導入模塊,默認使用 webpack v4+ 提供的全新的通用分塊策略(common chunk strategy)。請在 SplitChunksPlugin 頁面中查看配置其行為的可用選項。
export default {
optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
'default': false,
defaultVendors: false,
common: {
name: 'common',
minChunks: 2,
priority: 1
},
vendors: {
name: 'vendors',
minChunks: 2,
test: function () { /* omitted long function */ },
priority: 10
},
taro: {
name: 'taro',
test: module => helper_1.REG_TARO_SCOPED_PACKAGE.test(module.context),
priority: 100
}
}
},
}
}
splitChunks 切割分成 vendors、taro、common 文件(模塊)。也就是開頭入口文件 app.js 中,另外引入的文件。
4.6.2 optimization.minimizer
optimization.minimizer 允許你通過提供一個或多個定製過的 TerserPlugin 實例,覆蓋默認壓縮工具(minimizer)。
export default {
optimization: {
minimizer: [
/* config.optimization.minimizer('terserPlugin') */
new TerserPlugin(
{
parallel: true,
terserOptions: {
// 省略...
}
}
),
/* config.optimization.minimizer('cssoWebpackPlugin') */
new CssMinimizerPlugin(
{
test: /\.(css|scss|sass|less|styl|stylus|wxss|acss|ttss|jxss|qss)(\?.*)?$/,
parallel: true,
minify: function () { /* omitted long function */ },
minimizerOptions: {
preset: [
// 省略...
]
}
}
)
]
},
}
壓縮代碼插件 terser-webpack-plugin
壓縮 css 插件 css-minimizer-webpack-plugin
4.7 plugins 插件
plugins 選項用於以各種方式自定義 webpack 構建過程。webpack 附帶了各種內置插件,可以通過 webpack.[plugin-name] 訪問這些插件。請查看 插件頁面 獲取插件列表和對應文檔,但請注意這只是其中一部分,社區中還有許多插件。
export default {
plugins: [
/* config.plugin('webpackbar') */
new TaroWebpackBarPlugin(
{
reporters: [
'basic',
'fancy',
{
done: function () { /* omitted long function */ }
}
],
basic: false,
fancy: true
}
),
// 省略,拆開放到下文
],
}
TaroWebpackBarPlugin 繼承自 WebpackBar(優雅的進度條),避免因持久化緩存 IdleFileCachePlugin 再度觸發 progress 事件,導致 webpackbar 在 100% 後又再渲染的問題。
4.7.1 ProvidePlugin 自動加載模塊
webpack.ProvidePlugin 自動加載模塊,而不必到處 import 加載 require 它們。
provide-plugin
new webpack.ProvidePlugin({
identifier: 'module1',
// ...
});
比如 jQuery。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
});
new webpack.ProvidePlugin({
identifier: ['module1', 'property1'],
// ...
});
// in a module
$('#item'); // <= works
jQuery('#item'); // <= also works
// $ is automatically set to the exports of module "jquery"
/* config.plugin('providerPlugin') */
new ProvidePlugin({
window: ['@tarojs/runtime', 'window'],
document: ['@tarojs/runtime', 'document'],
navigator: ['@tarojs/runtime', 'navigator'],
requestAnimationFrame: ['@tarojs/runtime', 'requestAnimationFrame'],
cancelAnimationFrame: ['@tarojs/runtime', 'cancelAnimationFrame'],
Element: ['@tarojs/runtime', 'TaroElement'],
SVGElement: ['@tarojs/runtime', 'SVGElement'],
MutationObserver: ['@tarojs/runtime','MutationObserver' ],
history: ['@tarojs/runtime', 'history'],
location: ['@tarojs/runtime','location'],
URLSearchParams: ['@tarojs/runtime', 'URLSearchParams'],
URL: ['@tarojs/runtime', 'URL']
}),
這樣我們在 Taro 項目中的任意地方寫 window、document、navigator 時。實際引用的是 @tarojs/runtime 運行時中模擬實現的。
4.7.2 DefinePlugin
DefinePlugin 允許在 編譯時 將你代碼中的變量替換為其他值或表達式。這在需要根據開發模式與生產模式進行不同的操作時,非常有用。例如,如果想在開發構建中進行日誌記錄,而不在生產構建中進行,就可以定義一個全局常量去判斷是否記錄日誌。這就是 DefinePlugin 的發光之處,設置好它,就可以忘掉開發環境和生產環境的構建規則。
/* config.plugin('definePlugin') */
new DefinePlugin({
'process.env.FRAMEWORK': '"react"',
'process.env.TARO_ENV': '"weapp"',
'process.env.TARO_PLATFORM': '"mini"',
'process.env.TARO_VERSION': '"4.0.7"',
'process.env.SUPPORT_TARO_POLYFILL': '"disabled"',
ENABLE_INNER_HTML: true,
ENABLE_ADJACENT_HTML: false,
ENABLE_SIZE_APIS: false,
ENABLE_TEMPLATE_CONTENT: false,
ENABLE_CLONE_NODE: false,
ENABLE_CONTAINS: false,
ENABLE_MUTATION_OBSERVER: false
}),
4.7.3 MiniCssExtractPlugin 提取 css 到單獨文件中
mini-css-extract-plugin 此插件將 CSS 提取到單獨的文件中。它為每個包含 CSS 的 JS 文件創建一個 CSS 文件。它支持 CSS 和 SourceMaps 的按需加載。
/* config.plugin('miniCssExtractPlugin') */
new MiniCssExtractPlugin({
filename: '[name].wxss',
chunkFilename: '[name].wxss'
}),
4.7.4 MiniSplitChunksPlugin
import SplitChunksPlugin from 'webpack/lib/optimize/SplitChunksPlugin'
繼承 SplitChunksPlugin 的插件,用於將分包公共依賴提取到單獨的文件中
/* config.plugin('miniSplitChunksPlugin') */
new MiniSplitChunksPlugin({
exclude: undefined,
fileType: {
templ: '.wxml',
style: '.wxss',
config: '.json',
script: '.js',
xs: '.wxs'
},
combination: {
// 省略...
}
}),
4.7.5 TaroMiniPlugin taro 插件
/* config.plugin('miniPlugin') */
new TaroMiniPlugin({
commonChunks: [
'runtime',
'vendors',
'taro',
'common'
],
constantsReplaceList: {
'process.env.FRAMEWORK': '"react"',
// 省略若干代碼
},
pxTransformConfig: {
platform: 'weapp',
designWidth: 750,
deviceRatio: {
'375': 2,
'640': 1.17,
'750': 1,
'828': 0.905
}
},
hot: false,
combination: {
// 省略...
},
loaderMeta: {
// 省略...
}
})
對應的源碼路徑是
// packages/taro-webpack5-runner/src/plugins/MiniPlugin.ts
export default class TaroMiniPlugin {
// ...
}
4.8 devtool
export default {
devtool: false,
target: [
'web',
'es5'
],
watchOptions: {
aggregateTimeout: 200
},
performance: {
maxEntrypointSize: 2000000
},
}
devtool 此選項控制是否生成,以及如何生成 source map。
使用 SourceMapDevToolPlugin 進行更細粒度的配置。查看 source-map-loader 來處理已有的 source map。
4.9 target 構建目標
構建目標(Targets)
webpack 能夠為多種環境或 target 構建編譯。想要理解什麼是 target 的詳細信息, 請閲讀 target 概念頁面。
4.10 watchOptions 監測選項
Webpack 可以監聽文件變化,當它們修改後會重新編譯。這個頁面介紹瞭如何啓用這個功能,以及當 watch 無法正常運行的時候你可以做的一些調整。
4.11 performance 性能
這些選項可以控制 webpack 如何通知「資源(asset)和入口起點超過指定文件限制」。 此功能受到 webpack 性能評估的啓發。
5. 總結
行文至此,我們來總結下本文內容。
通過 npx @tarojs/cli@latest init taro4-debug 初始化項目。
通過 cd taro4-debug && npx taro -h 得知 inspect 命令,可以指定平台和路徑,輸出項目中的 webpack 配置。
npx taro inspect -t weapp -o webpack.config.js
根據文檔,分析了 webpack 配置,包括 entry、mode、output、 module、 resolve、optimization、plugins 等配置。
{
entry: {
app: [
'/Users/ruochuan/git-source/github/taro4-debug/src/app.ts'
]
}
}
打包後入口文件生成 app.js。
module 配置 rules 針對各種文件使用相應的 loader 解析文件。比如圖片、字體文件、視頻文件,less、sass、js 等。
針對小程序特定的文件類型,寫了特定的 loader 進行處理。
- tempate => miniTemplateLoader => 源碼路徑 packages/taro-webpack5-runner/src/loaders/miniTemplateLoader.ts
- wxs => miniXScriptLoader => 源碼路徑 packages/taro-webpack5-runner/src/loaders/miniXScriptLoader.ts
resolve 解析中的 alias 配置了 regenerator-runtime、@tarojs/runtime、@tarojs/shared、@tarojs/components$、react-dom$、react-dom/client$
optimization 優化中的 splitChunks 分割 common、taro、vendors 模塊,minimizer 配置了壓縮代碼插件 terser-webpack-plugin、壓縮 css 插件 css-minimizer-webpack-plugin
plugins 插件配置中,配置了 webpack.ProvidePlugin、DefinePlugin、MiniCssExtractPlugin 提取 css 到單獨文件中、MiniSplitChunksPlugin、TaroMiniPlugin 插件。
後續有時間再單獨寫文章,分析是如何組織成 webpack 配置的。
如果看完有收穫,歡迎點贊、評論、分享、收藏支持。你的支持和肯定,是我寫作的動力。也歡迎提建議和交流討論。
作者:常以若川為名混跡於江湖。所知甚少,唯善學。若川的博客,github blog,可以點個 star 鼓勵下持續創作。
最後可以持續關注我@若川,歡迎關注我的公眾號:若川視野。從 2021 年 8 月起,我持續組織了好幾年的每週大家一起學習 200 行左右的源碼共讀活動,感興趣的可以點此掃碼加我微信 ruochuan02 參與。另外,想學源碼,極力推薦關注我寫的專欄《學習源碼整體架構系列》,目前是掘金關注人數(6k+人)第一的專欄,寫有幾十篇源碼文章。