[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fcompany":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fcompany":2693,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fcompany":2719},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":2689,"stem":2690,"id":2691,"extension":2692},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fcompany","企业级实践","大型前端项目在 Webpack 场景下的多环境拆分、Docker 构建缓存、自定义 CLI 与微前端（Module Federation \u002F single-spa）等实践。入门见 工程化概览。","技能小册",[12,13],"webpack","company","2024-07-30",false,{"type":17,"value":18,"toc":2681},"minimark",[19,22,32,37,45,50,60,67,267,411,419,429,497,503,689,693,696,700,786,790,797,881,884,899,906,958,962,995,999,1009,1013,1557,1565,1733,1737,1760,1764,1767,1771,1778,1948,1953,2100,2104,2120,2125,2345,2350,2484,2488,2513,2517,2534,2538,2619,2622,2625,2628,2677],[20,21,8],"h1",{"id":8},[23,24,25,26,31],"p",{},"大型前端项目在 Webpack 场景下的多环境拆分、Docker 构建缓存、自定义 CLI 与微前端（Module Federation \u002F single-spa）等实践。入门见 ",[27,28,30],"a",{"href":29},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fbasics","工程化概览","。",[33,34,36],"h3",{"id":35},"一多环境配置拆分","一、多环境配置拆分",[23,38,39,40,44],{},"生产、开发、测试等环境往往需要不同的配置（API 地址、source map 策略、优化选项等）。推荐使用 ",[41,42,43],"code",{},"webpack-merge"," 将公共配置与环境特定配置分离。",[46,47,49],"h4",{"id":48},"_1-文件结构","1. 文件结构",[51,52,57],"pre",{"className":53,"code":55,"language":56},[54],"language-text","build\u002F\n  webpack.common.js   # 公共配置（entry、output、module.rules）\n  webpack.dev.js      # 开发配置（devServer、cheap-source-map）\n  webpack.prod.js     # 生产配置（压缩、contenthash、splitChunks）\n","text",[41,58,55],{"__ignoreMap":59},"",[46,61,63,64,66],{"id":62},"_2-使用-webpack-merge-合并","2. 使用 ",[41,65,43],{}," 合并",[51,68,72],{"className":69,"code":70,"language":71,"meta":59,"style":59},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F webpack.dev.js\nconst { merge } = require(\"webpack-merge\");\nconst common = require(\".\u002Fwebpack.common.js\");\n\nmodule.exports = merge(common, {\n  mode: \"development\",\n  devtool: \"eval-cheap-module-source-map\",\n  devServer: { hot: true, port: 8080 },\n});\n","js",[41,73,74,83,128,153,160,186,207,224,257],{"__ignoreMap":59},[75,76,79],"span",{"class":77,"line":78},"line",1,[75,80,82],{"class":81},"sutJx","\u002F\u002F webpack.dev.js\n",[75,84,86,90,94,98,101,105,109,113,117,120,122,125],{"class":77,"line":85},2,[75,87,89],{"class":88},"sbsja","const",[75,91,93],{"class":92},"sP7_E"," {",[75,95,97],{"class":96},"s_hVV"," merge",[75,99,100],{"class":92}," }",[75,102,104],{"class":103},"smGrS"," =",[75,106,108],{"class":107},"sGLFI"," require",[75,110,112],{"class":111},"su5hD","(",[75,114,116],{"class":115},"sjJ54","\"",[75,118,43],{"class":119},"s_sjI",[75,121,116],{"class":115},[75,123,124],{"class":111},")",[75,126,127],{"class":92},";\n",[75,129,131,133,136,138,140,142,144,147,149,151],{"class":77,"line":130},3,[75,132,89],{"class":88},[75,134,135],{"class":96}," common",[75,137,104],{"class":103},[75,139,108],{"class":107},[75,141,112],{"class":111},[75,143,116],{"class":115},[75,145,146],{"class":119},".\u002Fwebpack.common.js",[75,148,116],{"class":115},[75,150,124],{"class":111},[75,152,127],{"class":92},[75,154,156],{"class":77,"line":155},4,[75,157,159],{"emptyLinePlaceholder":158},true,"\n",[75,161,163,167,170,173,175,177,180,183],{"class":77,"line":162},5,[75,164,166],{"class":165},"s39Yj","module",[75,168,169],{"class":92},".",[75,171,172],{"class":165},"exports",[75,174,104],{"class":103},[75,176,97],{"class":107},[75,178,179],{"class":111},"(common",[75,181,182],{"class":92},",",[75,184,185],{"class":92}," {\n",[75,187,189,193,196,199,202,204],{"class":77,"line":188},6,[75,190,192],{"class":191},"skxfh","  mode",[75,194,195],{"class":92},":",[75,197,198],{"class":115}," \"",[75,200,201],{"class":119},"development",[75,203,116],{"class":115},[75,205,206],{"class":92},",\n",[75,208,210,213,215,217,220,222],{"class":77,"line":209},7,[75,211,212],{"class":191},"  devtool",[75,214,195],{"class":92},[75,216,198],{"class":115},[75,218,219],{"class":119},"eval-cheap-module-source-map",[75,221,116],{"class":115},[75,223,206],{"class":92},[75,225,227,230,232,234,237,239,243,245,248,250,254],{"class":77,"line":226},8,[75,228,229],{"class":191},"  devServer",[75,231,195],{"class":92},[75,233,93],{"class":92},[75,235,236],{"class":191}," hot",[75,238,195],{"class":92},[75,240,242],{"class":241},"syTEX"," true",[75,244,182],{"class":92},[75,246,247],{"class":191}," port",[75,249,195],{"class":92},[75,251,253],{"class":252},"srdBf"," 8080",[75,255,256],{"class":92}," },\n",[75,258,260,263,265],{"class":77,"line":259},9,[75,261,262],{"class":92},"}",[75,264,124],{"class":111},[75,266,127],{"class":92},[51,268,270],{"className":69,"code":269,"language":71,"meta":59,"style":59},"\u002F\u002F webpack.prod.js\nconst { merge } = require(\"webpack-merge\");\nconst common = require(\".\u002Fwebpack.common.js\");\n\nmodule.exports = merge(common, {\n  mode: \"production\",\n  output: { filename: \"[name].[contenthash].js\" },\n  optimization: { minimize: true },\n});\n",[41,271,272,277,303,325,329,347,362,385,403],{"__ignoreMap":59},[75,273,274],{"class":77,"line":78},[75,275,276],{"class":81},"\u002F\u002F webpack.prod.js\n",[75,278,279,281,283,285,287,289,291,293,295,297,299,301],{"class":77,"line":85},[75,280,89],{"class":88},[75,282,93],{"class":92},[75,284,97],{"class":96},[75,286,100],{"class":92},[75,288,104],{"class":103},[75,290,108],{"class":107},[75,292,112],{"class":111},[75,294,116],{"class":115},[75,296,43],{"class":119},[75,298,116],{"class":115},[75,300,124],{"class":111},[75,302,127],{"class":92},[75,304,305,307,309,311,313,315,317,319,321,323],{"class":77,"line":130},[75,306,89],{"class":88},[75,308,135],{"class":96},[75,310,104],{"class":103},[75,312,108],{"class":107},[75,314,112],{"class":111},[75,316,116],{"class":115},[75,318,146],{"class":119},[75,320,116],{"class":115},[75,322,124],{"class":111},[75,324,127],{"class":92},[75,326,327],{"class":77,"line":155},[75,328,159],{"emptyLinePlaceholder":158},[75,330,331,333,335,337,339,341,343,345],{"class":77,"line":162},[75,332,166],{"class":165},[75,334,169],{"class":92},[75,336,172],{"class":165},[75,338,104],{"class":103},[75,340,97],{"class":107},[75,342,179],{"class":111},[75,344,182],{"class":92},[75,346,185],{"class":92},[75,348,349,351,353,355,358,360],{"class":77,"line":188},[75,350,192],{"class":191},[75,352,195],{"class":92},[75,354,198],{"class":115},[75,356,357],{"class":119},"production",[75,359,116],{"class":115},[75,361,206],{"class":92},[75,363,364,367,369,371,374,376,378,381,383],{"class":77,"line":209},[75,365,366],{"class":191},"  output",[75,368,195],{"class":92},[75,370,93],{"class":92},[75,372,373],{"class":191}," filename",[75,375,195],{"class":92},[75,377,198],{"class":115},[75,379,380],{"class":119},"[name].[contenthash].js",[75,382,116],{"class":115},[75,384,256],{"class":92},[75,386,387,390,392,394,397,399,401],{"class":77,"line":226},[75,388,389],{"class":191},"  optimization",[75,391,195],{"class":92},[75,393,93],{"class":92},[75,395,396],{"class":191}," minimize",[75,398,195],{"class":92},[75,400,242],{"class":241},[75,402,256],{"class":92},[75,404,405,407,409],{"class":77,"line":259},[75,406,262],{"class":92},[75,408,124],{"class":111},[75,410,127],{"class":92},[46,412,414,415,418],{"id":413},"_3-通过-env-传递环境变量","3. 通过 ",[41,416,417],{},"--env"," 传递环境变量",[23,420,421,422,425,426,428],{},"在 ",[41,423,424],{},"package.json"," 中使用 ",[41,427,417],{}," 参数：",[51,430,434],{"className":431,"code":432,"language":433,"meta":59,"style":59},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","\"scripts\": {\n  \"build:dev\": \"webpack --env production=false --config build\u002Fwebpack.common.js\",\n  \"build:prod\": \"webpack --env production=true\"\n}\n","json",[41,435,436,451,473,492],{"__ignoreMap":59},[75,437,438,440,443,445,448],{"class":77,"line":78},[75,439,116],{"class":115},[75,441,442],{"class":119},"scripts",[75,444,116],{"class":115},[75,446,447],{"class":111},": ",[75,449,450],{"class":92},"{\n",[75,452,453,456,460,462,464,466,469,471],{"class":77,"line":85},[75,454,455],{"class":165},"  \"",[75,457,459],{"class":458},"sseR_","build:dev",[75,461,116],{"class":165},[75,463,195],{"class":92},[75,465,198],{"class":115},[75,467,468],{"class":119},"webpack --env production=false --config build\u002Fwebpack.common.js",[75,470,116],{"class":115},[75,472,206],{"class":92},[75,474,475,477,480,482,484,486,489],{"class":77,"line":130},[75,476,455],{"class":165},[75,478,479],{"class":458},"build:prod",[75,481,116],{"class":165},[75,483,195],{"class":92},[75,485,198],{"class":115},[75,487,488],{"class":119},"webpack --env production=true",[75,490,491],{"class":115},"\"\n",[75,493,494],{"class":77,"line":155},[75,495,496],{"class":92},"}\n",[23,498,499,500,428],{},"Webpack 配置接收 ",[41,501,502],{},"env",[51,504,506],{"className":69,"code":505,"language":71,"meta":59,"style":59},"\u002F\u002F webpack.common.js\nmodule.exports = (env, argv) => {\n  const isProd = env.production;\n  return {\n    \u002F\u002F ... 公共配置\n    plugins: [\n      new webpack.DefinePlugin({\n        \"process.env.API_BASE\": JSON.stringify(\n          isProd ? \"https:\u002F\u002Fapi.prod.com\" : \"https:\u002F\u002Fapi.dev.com\",\n        ),\n      }),\n    ],\n  };\n};\n",[41,507,508,513,541,560,568,573,583,600,624,651,659,669,677,683],{"__ignoreMap":59},[75,509,510],{"class":77,"line":78},[75,511,512],{"class":81},"\u002F\u002F webpack.common.js\n",[75,514,515,517,519,521,523,526,529,531,534,536,539],{"class":77,"line":85},[75,516,166],{"class":165},[75,518,169],{"class":92},[75,520,172],{"class":165},[75,522,104],{"class":103},[75,524,525],{"class":92}," (",[75,527,502],{"class":528},"s99_P",[75,530,182],{"class":92},[75,532,533],{"class":528}," argv",[75,535,124],{"class":92},[75,537,538],{"class":88}," =>",[75,540,185],{"class":92},[75,542,543,546,549,551,554,556,558],{"class":77,"line":130},[75,544,545],{"class":88},"  const",[75,547,548],{"class":96}," isProd",[75,550,104],{"class":103},[75,552,553],{"class":111}," env",[75,555,169],{"class":92},[75,557,357],{"class":111},[75,559,127],{"class":92},[75,561,562,566],{"class":77,"line":155},[75,563,565],{"class":564},"sVHd0","  return",[75,567,185],{"class":92},[75,569,570],{"class":77,"line":162},[75,571,572],{"class":81},"    \u002F\u002F ... 公共配置\n",[75,574,575,578,580],{"class":77,"line":188},[75,576,577],{"class":191},"    plugins",[75,579,195],{"class":92},[75,581,582],{"class":191}," [\n",[75,584,585,588,591,593,596,598],{"class":77,"line":209},[75,586,587],{"class":103},"      new",[75,589,590],{"class":111}," webpack",[75,592,169],{"class":92},[75,594,595],{"class":107},"DefinePlugin",[75,597,112],{"class":191},[75,599,450],{"class":92},[75,601,602,605,609,611,613,616,618,621],{"class":77,"line":226},[75,603,604],{"class":115},"        \"",[75,606,608],{"class":607},"sZUrc","process.env.API_BASE",[75,610,116],{"class":115},[75,612,195],{"class":92},[75,614,615],{"class":96}," JSON",[75,617,169],{"class":92},[75,619,620],{"class":107},"stringify",[75,622,623],{"class":191},"(\n",[75,625,626,629,632,634,637,639,642,644,647,649],{"class":77,"line":259},[75,627,628],{"class":111},"          isProd",[75,630,631],{"class":103}," ?",[75,633,198],{"class":115},[75,635,636],{"class":119},"https:\u002F\u002Fapi.prod.com",[75,638,116],{"class":115},[75,640,641],{"class":103}," :",[75,643,198],{"class":115},[75,645,646],{"class":119},"https:\u002F\u002Fapi.dev.com",[75,648,116],{"class":115},[75,650,206],{"class":92},[75,652,654,657],{"class":77,"line":653},10,[75,655,656],{"class":191},"        )",[75,658,206],{"class":92},[75,660,662,665,667],{"class":77,"line":661},11,[75,663,664],{"class":92},"      }",[75,666,124],{"class":191},[75,668,206],{"class":92},[75,670,672,675],{"class":77,"line":671},12,[75,673,674],{"class":191},"    ]",[75,676,206],{"class":92},[75,678,680],{"class":77,"line":679},13,[75,681,682],{"class":92},"  };\n",[75,684,686],{"class":77,"line":685},14,[75,687,688],{"class":92},"};\n",[33,690,692],{"id":691},"二构建流程的-docker-化","二、构建流程的 Docker 化",[23,694,695],{},"将 Webpack 构建封装到 Docker 中，可以保证环境一致性，并利用缓存加速 CI。",[46,697,699],{"id":698},"_1-多阶段构建-dockerfile","1. 多阶段构建 Dockerfile",[51,701,705],{"className":702,"code":703,"language":704,"meta":59,"style":59},"language-dockerfile shiki shiki-themes material-theme-lighter github-light github-dark","# 第一阶段：安装依赖（缓存 node_modules）\nFROM node:22-alpine AS deps\nWORKDIR \u002Fapp\nCOPY package.json package-lock.json .\u002F\nRUN npm ci --only=production\n\n# 第二阶段：开发\u002F构建阶段\nFROM node:22-alpine AS builder\nWORKDIR \u002Fapp\nCOPY --from=deps \u002Fapp\u002Fnode_modules .\u002Fnode_modules\nCOPY . .\nRUN npm run build\n\n# 第三阶段：生产运行（可选，若只需构建产物）\nFROM nginx:alpine\nCOPY --from=builder \u002Fapp\u002Fdist \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\n","dockerfile",[41,706,707,712,717,722,727,732,736,741,746,750,755,760,765,769,774,780],{"__ignoreMap":59},[75,708,709],{"class":77,"line":78},[75,710,711],{},"# 第一阶段：安装依赖（缓存 node_modules）\n",[75,713,714],{"class":77,"line":85},[75,715,716],{},"FROM node:22-alpine AS deps\n",[75,718,719],{"class":77,"line":130},[75,720,721],{},"WORKDIR \u002Fapp\n",[75,723,724],{"class":77,"line":155},[75,725,726],{},"COPY package.json package-lock.json .\u002F\n",[75,728,729],{"class":77,"line":162},[75,730,731],{},"RUN npm ci --only=production\n",[75,733,734],{"class":77,"line":188},[75,735,159],{"emptyLinePlaceholder":158},[75,737,738],{"class":77,"line":209},[75,739,740],{},"# 第二阶段：开发\u002F构建阶段\n",[75,742,743],{"class":77,"line":226},[75,744,745],{},"FROM node:22-alpine AS builder\n",[75,747,748],{"class":77,"line":259},[75,749,721],{},[75,751,752],{"class":77,"line":653},[75,753,754],{},"COPY --from=deps \u002Fapp\u002Fnode_modules .\u002Fnode_modules\n",[75,756,757],{"class":77,"line":661},[75,758,759],{},"COPY . .\n",[75,761,762],{"class":77,"line":671},[75,763,764],{},"RUN npm run build\n",[75,766,767],{"class":77,"line":679},[75,768,159],{"emptyLinePlaceholder":158},[75,770,771],{"class":77,"line":685},[75,772,773],{},"# 第三阶段：生产运行（可选，若只需构建产物）\n",[75,775,777],{"class":77,"line":776},15,[75,778,779],{},"FROM nginx:alpine\n",[75,781,783],{"class":77,"line":782},16,[75,784,785],{},"COPY --from=builder \u002Fapp\u002Fdist \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\n",[46,787,789],{"id":788},"_2-利用-webpack-持久化缓存优化-ci","2. 利用 Webpack 持久化缓存优化 CI",[23,791,792,793,796],{},"Webpack 5 支持 ",[41,794,795],{},"cache: filesystem","，可以将模块编译结果缓存到磁盘，加速二次构建。",[51,798,800],{"className":69,"code":799,"language":71,"meta":59,"style":59},"\u002F\u002F webpack.common.js\nmodule.exports = {\n  cache: {\n    type: \"filesystem\",\n    buildDependencies: {\n      config: [__filename], \u002F\u002F 配置文件变化时重新缓存\n    },\n  },\n};\n",[41,801,802,806,818,827,843,852,867,872,877],{"__ignoreMap":59},[75,803,804],{"class":77,"line":78},[75,805,512],{"class":81},[75,807,808,810,812,814,816],{"class":77,"line":85},[75,809,166],{"class":165},[75,811,169],{"class":92},[75,813,172],{"class":165},[75,815,104],{"class":103},[75,817,185],{"class":92},[75,819,820,823,825],{"class":77,"line":130},[75,821,822],{"class":191},"  cache",[75,824,195],{"class":92},[75,826,185],{"class":92},[75,828,829,832,834,836,839,841],{"class":77,"line":155},[75,830,831],{"class":191},"    type",[75,833,195],{"class":92},[75,835,198],{"class":115},[75,837,838],{"class":119},"filesystem",[75,840,116],{"class":115},[75,842,206],{"class":92},[75,844,845,848,850],{"class":77,"line":162},[75,846,847],{"class":191},"    buildDependencies",[75,849,195],{"class":92},[75,851,185],{"class":92},[75,853,854,857,859,862,864],{"class":77,"line":188},[75,855,856],{"class":191},"      config",[75,858,195],{"class":92},[75,860,861],{"class":111}," [__filename]",[75,863,182],{"class":92},[75,865,866],{"class":81}," \u002F\u002F 配置文件变化时重新缓存\n",[75,868,869],{"class":77,"line":209},[75,870,871],{"class":92},"    },\n",[75,873,874],{"class":77,"line":226},[75,875,876],{"class":92},"  },\n",[75,878,879],{"class":77,"line":259},[75,880,688],{"class":92},[23,882,883],{},"在 Docker 中，可以将缓存目录挂载为卷，保留跨构建的缓存：",[51,885,887],{"className":702,"code":886,"language":704,"meta":59,"style":59},"# 构建时挂载 cache 目录\nRUN --mount=type=cache,target=\u002Fapp\u002Fnode_modules\u002F.cache\u002Fwebpack npm run build\n",[41,888,889,894],{"__ignoreMap":59},[75,890,891],{"class":77,"line":78},[75,892,893],{},"# 构建时挂载 cache 目录\n",[75,895,896],{"class":77,"line":85},[75,897,898],{},"RUN --mount=type=cache,target=\u002Fapp\u002Fnode_modules\u002F.cache\u002Fwebpack npm run build\n",[23,900,901,902,905],{},"或在 ",[41,903,904],{},"docker-compose.yml"," 中：",[51,907,911],{"className":908,"code":909,"language":910,"meta":59,"style":59},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark","services:\n  build:\n    volumes:\n      - webpack_cache:\u002Fapp\u002Fnode_modules\u002F.cache\u002Fwebpack\nvolumes:\n  webpack_cache:\n","yaml",[41,912,913,922,929,936,944,951],{"__ignoreMap":59},[75,914,915,919],{"class":77,"line":78},[75,916,918],{"class":917},"sQzsp","services",[75,920,921],{"class":92},":\n",[75,923,924,927],{"class":77,"line":85},[75,925,926],{"class":917},"  build",[75,928,921],{"class":92},[75,930,931,934],{"class":77,"line":130},[75,932,933],{"class":917},"    volumes",[75,935,921],{"class":92},[75,937,938,941],{"class":77,"line":155},[75,939,940],{"class":92},"      -",[75,942,943],{"class":119}," webpack_cache:\u002Fapp\u002Fnode_modules\u002F.cache\u002Fwebpack\n",[75,945,946,949],{"class":77,"line":162},[75,947,948],{"class":917},"volumes",[75,950,921],{"class":92},[75,952,953,956],{"class":77,"line":188},[75,954,955],{"class":917},"  webpack_cache",[75,957,921],{"class":92},[46,959,961],{"id":960},"_3-ci-优化技巧","3. CI 优化技巧",[963,964,965,977,992],"ul",{},[966,967,968,969,972,973,976],"li",{},"使用 ",[41,970,971],{},"npm ci"," 替代 ",[41,974,975],{},"npm install","（严格依据 lockfile，更快）。",[966,978,979,980,983,984,987,988,991],{},"对 ",[41,981,982],{},"node_modules"," 进行缓存（GitLab CI: ",[41,985,986],{},"cache","、GitHub Actions: ",[41,989,990],{},"actions\u002Fcache","）。",[966,993,994],{},"将 Webpack 构建与 Docker 镜像构建分离，只打包 dist 到最终镜像。",[33,996,998],{"id":997},"三自定义-cli-封装","三、自定义 CLI 封装",[23,1000,1001,1002,1004,1005,1008],{},"对于中大型团队，往往需要封装内部脚手架，统一构建规范。可以基于 ",[41,1003,12],{}," Node API + ",[41,1006,1007],{},"commander"," 实现。",[46,1010,1012],{"id":1011},"_1-基本结构","1. 基本结构",[51,1014,1016],{"className":69,"code":1015,"language":71,"meta":59,"style":59},"\u002F\u002F bin\u002Fcli.js\n#!\u002Fusr\u002Fbin\u002Fenv node\nconst { program } = require('commander');\nconst webpack = require('webpack');\nconst devServer = require('webpack-dev-server');\nconst getConfig = require('..\u002Fconfig');\n\nprogram\n  .command('dev')\n  .description('启动开发服务器')\n  .action(() => {\n    const config = getConfig('development');\n    const compiler = webpack(config);\n    const server = new devServer(compiler, config.devServer);\n    server.start();\n  });\n\nprogram\n  .command('build')\n  .description('生产构建')\n  .option('-p, --production', '生产模式')\n  .action((options) => {\n    const config = getConfig('production');\n    webpack(config, (err, stats) => {\n      if (err) throw err;\n      console.log(stats.toString({ colors: true }));\n    });\n  });\n\nprogram.parse(process.argv);\n",[41,1017,1018,1023,1045,1073,1095,1119,1143,1147,1152,1172,1190,1206,1230,1250,1282,1296,1305,1310,1315,1333,1351,1380,1400,1423,1451,1472,1512,1522,1531,1536],{"__ignoreMap":59},[75,1019,1020],{"class":77,"line":78},[75,1021,1022],{"class":81},"\u002F\u002F bin\u002Fcli.js\n",[75,1024,1025,1028,1031,1034,1037,1040,1042],{"class":77,"line":85},[75,1026,1027],{"class":111},"#",[75,1029,1030],{"class":103},"!\u002F",[75,1032,1033],{"class":111},"usr",[75,1035,1036],{"class":103},"\u002F",[75,1038,1039],{"class":111},"bin",[75,1041,1036],{"class":103},[75,1043,1044],{"class":111},"env node\n",[75,1046,1047,1049,1051,1054,1056,1058,1060,1062,1065,1067,1069,1071],{"class":77,"line":130},[75,1048,89],{"class":88},[75,1050,93],{"class":92},[75,1052,1053],{"class":96}," program",[75,1055,100],{"class":92},[75,1057,104],{"class":103},[75,1059,108],{"class":107},[75,1061,112],{"class":111},[75,1063,1064],{"class":115},"'",[75,1066,1007],{"class":119},[75,1068,1064],{"class":115},[75,1070,124],{"class":111},[75,1072,127],{"class":92},[75,1074,1075,1077,1079,1081,1083,1085,1087,1089,1091,1093],{"class":77,"line":155},[75,1076,89],{"class":88},[75,1078,590],{"class":96},[75,1080,104],{"class":103},[75,1082,108],{"class":107},[75,1084,112],{"class":111},[75,1086,1064],{"class":115},[75,1088,12],{"class":119},[75,1090,1064],{"class":115},[75,1092,124],{"class":111},[75,1094,127],{"class":92},[75,1096,1097,1099,1102,1104,1106,1108,1110,1113,1115,1117],{"class":77,"line":162},[75,1098,89],{"class":88},[75,1100,1101],{"class":96}," devServer",[75,1103,104],{"class":103},[75,1105,108],{"class":107},[75,1107,112],{"class":111},[75,1109,1064],{"class":115},[75,1111,1112],{"class":119},"webpack-dev-server",[75,1114,1064],{"class":115},[75,1116,124],{"class":111},[75,1118,127],{"class":92},[75,1120,1121,1123,1126,1128,1130,1132,1134,1137,1139,1141],{"class":77,"line":188},[75,1122,89],{"class":88},[75,1124,1125],{"class":96}," getConfig",[75,1127,104],{"class":103},[75,1129,108],{"class":107},[75,1131,112],{"class":111},[75,1133,1064],{"class":115},[75,1135,1136],{"class":119},"..\u002Fconfig",[75,1138,1064],{"class":115},[75,1140,124],{"class":111},[75,1142,127],{"class":92},[75,1144,1145],{"class":77,"line":209},[75,1146,159],{"emptyLinePlaceholder":158},[75,1148,1149],{"class":77,"line":226},[75,1150,1151],{"class":111},"program\n",[75,1153,1154,1157,1160,1162,1164,1167,1169],{"class":77,"line":259},[75,1155,1156],{"class":92},"  .",[75,1158,1159],{"class":107},"command",[75,1161,112],{"class":111},[75,1163,1064],{"class":115},[75,1165,1166],{"class":119},"dev",[75,1168,1064],{"class":115},[75,1170,1171],{"class":111},")\n",[75,1173,1174,1176,1179,1181,1183,1186,1188],{"class":77,"line":653},[75,1175,1156],{"class":92},[75,1177,1178],{"class":107},"description",[75,1180,112],{"class":111},[75,1182,1064],{"class":115},[75,1184,1185],{"class":119},"启动开发服务器",[75,1187,1064],{"class":115},[75,1189,1171],{"class":111},[75,1191,1192,1194,1197,1199,1202,1204],{"class":77,"line":661},[75,1193,1156],{"class":92},[75,1195,1196],{"class":107},"action",[75,1198,112],{"class":111},[75,1200,1201],{"class":92},"()",[75,1203,538],{"class":88},[75,1205,185],{"class":92},[75,1207,1208,1211,1214,1216,1218,1220,1222,1224,1226,1228],{"class":77,"line":671},[75,1209,1210],{"class":88},"    const",[75,1212,1213],{"class":96}," config",[75,1215,104],{"class":103},[75,1217,1125],{"class":107},[75,1219,112],{"class":191},[75,1221,1064],{"class":115},[75,1223,201],{"class":119},[75,1225,1064],{"class":115},[75,1227,124],{"class":191},[75,1229,127],{"class":92},[75,1231,1232,1234,1237,1239,1241,1243,1246,1248],{"class":77,"line":679},[75,1233,1210],{"class":88},[75,1235,1236],{"class":96}," compiler",[75,1238,104],{"class":103},[75,1240,590],{"class":107},[75,1242,112],{"class":191},[75,1244,1245],{"class":111},"config",[75,1247,124],{"class":191},[75,1249,127],{"class":92},[75,1251,1252,1254,1257,1259,1262,1264,1266,1269,1271,1273,1275,1278,1280],{"class":77,"line":685},[75,1253,1210],{"class":88},[75,1255,1256],{"class":96}," server",[75,1258,104],{"class":103},[75,1260,1261],{"class":103}," new",[75,1263,1101],{"class":107},[75,1265,112],{"class":191},[75,1267,1268],{"class":111},"compiler",[75,1270,182],{"class":92},[75,1272,1213],{"class":111},[75,1274,169],{"class":92},[75,1276,1277],{"class":111},"devServer",[75,1279,124],{"class":191},[75,1281,127],{"class":92},[75,1283,1284,1287,1289,1292,1294],{"class":77,"line":776},[75,1285,1286],{"class":111},"    server",[75,1288,169],{"class":92},[75,1290,1291],{"class":107},"start",[75,1293,1201],{"class":191},[75,1295,127],{"class":92},[75,1297,1298,1301,1303],{"class":77,"line":782},[75,1299,1300],{"class":92},"  }",[75,1302,124],{"class":111},[75,1304,127],{"class":92},[75,1306,1308],{"class":77,"line":1307},17,[75,1309,159],{"emptyLinePlaceholder":158},[75,1311,1313],{"class":77,"line":1312},18,[75,1314,1151],{"class":111},[75,1316,1318,1320,1322,1324,1326,1329,1331],{"class":77,"line":1317},19,[75,1319,1156],{"class":92},[75,1321,1159],{"class":107},[75,1323,112],{"class":111},[75,1325,1064],{"class":115},[75,1327,1328],{"class":119},"build",[75,1330,1064],{"class":115},[75,1332,1171],{"class":111},[75,1334,1336,1338,1340,1342,1344,1347,1349],{"class":77,"line":1335},20,[75,1337,1156],{"class":92},[75,1339,1178],{"class":107},[75,1341,112],{"class":111},[75,1343,1064],{"class":115},[75,1345,1346],{"class":119},"生产构建",[75,1348,1064],{"class":115},[75,1350,1171],{"class":111},[75,1352,1354,1356,1359,1361,1363,1366,1368,1370,1373,1376,1378],{"class":77,"line":1353},21,[75,1355,1156],{"class":92},[75,1357,1358],{"class":107},"option",[75,1360,112],{"class":111},[75,1362,1064],{"class":115},[75,1364,1365],{"class":119},"-p, --production",[75,1367,1064],{"class":115},[75,1369,182],{"class":92},[75,1371,1372],{"class":115}," '",[75,1374,1375],{"class":119},"生产模式",[75,1377,1064],{"class":115},[75,1379,1171],{"class":111},[75,1381,1383,1385,1387,1389,1391,1394,1396,1398],{"class":77,"line":1382},22,[75,1384,1156],{"class":92},[75,1386,1196],{"class":107},[75,1388,112],{"class":111},[75,1390,112],{"class":92},[75,1392,1393],{"class":528},"options",[75,1395,124],{"class":92},[75,1397,538],{"class":88},[75,1399,185],{"class":92},[75,1401,1403,1405,1407,1409,1411,1413,1415,1417,1419,1421],{"class":77,"line":1402},23,[75,1404,1210],{"class":88},[75,1406,1213],{"class":96},[75,1408,104],{"class":103},[75,1410,1125],{"class":107},[75,1412,112],{"class":191},[75,1414,1064],{"class":115},[75,1416,357],{"class":119},[75,1418,1064],{"class":115},[75,1420,124],{"class":191},[75,1422,127],{"class":92},[75,1424,1426,1429,1431,1433,1435,1437,1440,1442,1445,1447,1449],{"class":77,"line":1425},24,[75,1427,1428],{"class":107},"    webpack",[75,1430,112],{"class":191},[75,1432,1245],{"class":111},[75,1434,182],{"class":92},[75,1436,525],{"class":92},[75,1438,1439],{"class":528},"err",[75,1441,182],{"class":92},[75,1443,1444],{"class":528}," stats",[75,1446,124],{"class":92},[75,1448,538],{"class":88},[75,1450,185],{"class":92},[75,1452,1454,1457,1459,1461,1464,1467,1470],{"class":77,"line":1453},25,[75,1455,1456],{"class":564},"      if",[75,1458,525],{"class":191},[75,1460,1439],{"class":111},[75,1462,1463],{"class":191},") ",[75,1465,1466],{"class":564},"throw",[75,1468,1469],{"class":111}," err",[75,1471,127],{"class":92},[75,1473,1475,1478,1480,1483,1485,1488,1490,1493,1495,1498,1501,1503,1505,1507,1510],{"class":77,"line":1474},26,[75,1476,1477],{"class":111},"      console",[75,1479,169],{"class":92},[75,1481,1482],{"class":107},"log",[75,1484,112],{"class":191},[75,1486,1487],{"class":111},"stats",[75,1489,169],{"class":92},[75,1491,1492],{"class":107},"toString",[75,1494,112],{"class":191},[75,1496,1497],{"class":92},"{",[75,1499,1500],{"class":191}," colors",[75,1502,195],{"class":92},[75,1504,242],{"class":241},[75,1506,100],{"class":92},[75,1508,1509],{"class":191},"))",[75,1511,127],{"class":92},[75,1513,1515,1518,1520],{"class":77,"line":1514},27,[75,1516,1517],{"class":92},"    }",[75,1519,124],{"class":191},[75,1521,127],{"class":92},[75,1523,1525,1527,1529],{"class":77,"line":1524},28,[75,1526,1300],{"class":92},[75,1528,124],{"class":111},[75,1530,127],{"class":92},[75,1532,1534],{"class":77,"line":1533},29,[75,1535,159],{"emptyLinePlaceholder":158},[75,1537,1539,1542,1544,1547,1550,1552,1555],{"class":77,"line":1538},30,[75,1540,1541],{"class":111},"program",[75,1543,169],{"class":92},[75,1545,1546],{"class":107},"parse",[75,1548,1549],{"class":111},"(process",[75,1551,169],{"class":92},[75,1553,1554],{"class":111},"argv)",[75,1556,127],{"class":92},[46,1558,1560,1561,1564],{"id":1559},"_2-动态配置生成getconfig-函数","2. 动态配置生成（",[41,1562,1563],{},"getConfig"," 函数）",[51,1566,1568],{"className":69,"code":1567,"language":71,"meta":59,"style":59},"const { merge } = require(\"webpack-merge\");\nconst baseConfig = require(\"..\u002Fwebpack.common.js\");\n\nmodule.exports = (mode) => {\n  const envConfig =\n    mode === \"development\" ? require(\"..\u002Fwebpack.dev.js\") : require(\"..\u002Fwebpack.prod.js\");\n  return merge(baseConfig, envConfig, { mode });\n};\n",[41,1569,1570,1596,1620,1624,1645,1655,1701,1729],{"__ignoreMap":59},[75,1571,1572,1574,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594],{"class":77,"line":78},[75,1573,89],{"class":88},[75,1575,93],{"class":92},[75,1577,97],{"class":96},[75,1579,100],{"class":92},[75,1581,104],{"class":103},[75,1583,108],{"class":107},[75,1585,112],{"class":111},[75,1587,116],{"class":115},[75,1589,43],{"class":119},[75,1591,116],{"class":115},[75,1593,124],{"class":111},[75,1595,127],{"class":92},[75,1597,1598,1600,1603,1605,1607,1609,1611,1614,1616,1618],{"class":77,"line":85},[75,1599,89],{"class":88},[75,1601,1602],{"class":96}," baseConfig",[75,1604,104],{"class":103},[75,1606,108],{"class":107},[75,1608,112],{"class":111},[75,1610,116],{"class":115},[75,1612,1613],{"class":119},"..\u002Fwebpack.common.js",[75,1615,116],{"class":115},[75,1617,124],{"class":111},[75,1619,127],{"class":92},[75,1621,1622],{"class":77,"line":130},[75,1623,159],{"emptyLinePlaceholder":158},[75,1625,1626,1628,1630,1632,1634,1636,1639,1641,1643],{"class":77,"line":155},[75,1627,166],{"class":165},[75,1629,169],{"class":92},[75,1631,172],{"class":165},[75,1633,104],{"class":103},[75,1635,525],{"class":92},[75,1637,1638],{"class":528},"mode",[75,1640,124],{"class":92},[75,1642,538],{"class":88},[75,1644,185],{"class":92},[75,1646,1647,1649,1652],{"class":77,"line":162},[75,1648,545],{"class":88},[75,1650,1651],{"class":96}," envConfig",[75,1653,1654],{"class":103}," =\n",[75,1656,1657,1660,1663,1665,1667,1669,1671,1673,1675,1677,1680,1682,1684,1686,1688,1690,1692,1695,1697,1699],{"class":77,"line":188},[75,1658,1659],{"class":111},"    mode",[75,1661,1662],{"class":103}," ===",[75,1664,198],{"class":115},[75,1666,201],{"class":119},[75,1668,116],{"class":115},[75,1670,631],{"class":103},[75,1672,108],{"class":107},[75,1674,112],{"class":191},[75,1676,116],{"class":115},[75,1678,1679],{"class":119},"..\u002Fwebpack.dev.js",[75,1681,116],{"class":115},[75,1683,1463],{"class":191},[75,1685,195],{"class":103},[75,1687,108],{"class":107},[75,1689,112],{"class":191},[75,1691,116],{"class":115},[75,1693,1694],{"class":119},"..\u002Fwebpack.prod.js",[75,1696,116],{"class":115},[75,1698,124],{"class":191},[75,1700,127],{"class":92},[75,1702,1703,1705,1707,1709,1712,1714,1716,1718,1720,1723,1725,1727],{"class":77,"line":209},[75,1704,565],{"class":564},[75,1706,97],{"class":107},[75,1708,112],{"class":191},[75,1710,1711],{"class":111},"baseConfig",[75,1713,182],{"class":92},[75,1715,1651],{"class":111},[75,1717,182],{"class":92},[75,1719,93],{"class":92},[75,1721,1722],{"class":111}," mode",[75,1724,100],{"class":92},[75,1726,124],{"class":191},[75,1728,127],{"class":92},[75,1730,1731],{"class":77,"line":226},[75,1732,688],{"class":92},[46,1734,1736],{"id":1735},"_3-发布到-npm","3. 发布到 npm",[963,1738,1739,1750],{},[966,1740,421,1741,1743,1744,1746,1747],{},[41,1742,424],{}," 中设置 ",[41,1745,1039],{}," 字段：",[41,1748,1749],{},"\"bin\": { \"mycli\": \".\u002Fbin\u002Fcli.js\" }",[966,1751,1752,1753,1756,1757],{},"本地测试：",[41,1754,1755],{},"npm link"," 之后即可全局使用 ",[41,1758,1759],{},"mycli dev",[33,1761,1763],{"id":1762},"四微前端集成module-federation-single-spa","四、微前端集成：Module Federation + single-spa",[23,1765,1766],{},"目前主流的微前端方案之一是将 Webpack 5 的 Module Federation 与 single-spa 结合，实现主子应用独立开发部署，运行时共享依赖。",[46,1768,1770],{"id":1769},"_1-module-federation-配置","1. Module Federation 配置",[23,1772,1773,1777],{},[1774,1775,1776],"strong",{},"主应用（shell）","：",[51,1779,1781],{"className":69,"code":1780,"language":71,"meta":59,"style":59},"new ModuleFederationPlugin({\n  name: \"shell\",\n  remotes: {\n    app1: \"app1@http:\u002F\u002Flocalhost:3001\u002FremoteEntry.js\",\n    app2: \"app2@http:\u002F\u002Flocalhost:3002\u002FremoteEntry.js\",\n  },\n  shared: {\n    react: { singleton: true, eager: true, requiredVersion: \"^18.0.0\" },\n    \"react-dom\": { singleton: true, eager: true },\n  },\n});\n",[41,1782,1783,1795,1811,1820,1836,1852,1856,1865,1906,1936,1940],{"__ignoreMap":59},[75,1784,1785,1788,1791,1793],{"class":77,"line":78},[75,1786,1787],{"class":103},"new",[75,1789,1790],{"class":107}," ModuleFederationPlugin",[75,1792,112],{"class":111},[75,1794,450],{"class":92},[75,1796,1797,1800,1802,1804,1807,1809],{"class":77,"line":85},[75,1798,1799],{"class":191},"  name",[75,1801,195],{"class":92},[75,1803,198],{"class":115},[75,1805,1806],{"class":119},"shell",[75,1808,116],{"class":115},[75,1810,206],{"class":92},[75,1812,1813,1816,1818],{"class":77,"line":130},[75,1814,1815],{"class":191},"  remotes",[75,1817,195],{"class":92},[75,1819,185],{"class":92},[75,1821,1822,1825,1827,1829,1832,1834],{"class":77,"line":155},[75,1823,1824],{"class":191},"    app1",[75,1826,195],{"class":92},[75,1828,198],{"class":115},[75,1830,1831],{"class":119},"app1@http:\u002F\u002Flocalhost:3001\u002FremoteEntry.js",[75,1833,116],{"class":115},[75,1835,206],{"class":92},[75,1837,1838,1841,1843,1845,1848,1850],{"class":77,"line":162},[75,1839,1840],{"class":191},"    app2",[75,1842,195],{"class":92},[75,1844,198],{"class":115},[75,1846,1847],{"class":119},"app2@http:\u002F\u002Flocalhost:3002\u002FremoteEntry.js",[75,1849,116],{"class":115},[75,1851,206],{"class":92},[75,1853,1854],{"class":77,"line":188},[75,1855,876],{"class":92},[75,1857,1858,1861,1863],{"class":77,"line":209},[75,1859,1860],{"class":191},"  shared",[75,1862,195],{"class":92},[75,1864,185],{"class":92},[75,1866,1867,1870,1872,1874,1877,1879,1881,1883,1886,1888,1890,1892,1895,1897,1899,1902,1904],{"class":77,"line":226},[75,1868,1869],{"class":191},"    react",[75,1871,195],{"class":92},[75,1873,93],{"class":92},[75,1875,1876],{"class":191}," singleton",[75,1878,195],{"class":92},[75,1880,242],{"class":241},[75,1882,182],{"class":92},[75,1884,1885],{"class":191}," eager",[75,1887,195],{"class":92},[75,1889,242],{"class":241},[75,1891,182],{"class":92},[75,1893,1894],{"class":191}," requiredVersion",[75,1896,195],{"class":92},[75,1898,198],{"class":115},[75,1900,1901],{"class":119},"^18.0.0",[75,1903,116],{"class":115},[75,1905,256],{"class":92},[75,1907,1908,1911,1914,1916,1918,1920,1922,1924,1926,1928,1930,1932,1934],{"class":77,"line":259},[75,1909,1910],{"class":115},"    \"",[75,1912,1913],{"class":607},"react-dom",[75,1915,116],{"class":115},[75,1917,195],{"class":92},[75,1919,93],{"class":92},[75,1921,1876],{"class":191},[75,1923,195],{"class":92},[75,1925,242],{"class":241},[75,1927,182],{"class":92},[75,1929,1885],{"class":191},[75,1931,195],{"class":92},[75,1933,242],{"class":241},[75,1935,256],{"class":92},[75,1937,1938],{"class":77,"line":653},[75,1939,876],{"class":92},[75,1941,1942,1944,1946],{"class":77,"line":661},[75,1943,262],{"class":92},[75,1945,124],{"class":111},[75,1947,127],{"class":92},[23,1949,1950,1777],{},[1774,1951,1952],{},"子应用（app1）",[51,1954,1956],{"className":69,"code":1955,"language":71,"meta":59,"style":59},"new ModuleFederationPlugin({\n  name: \"app1\",\n  filename: \"remoteEntry.js\",\n  exposes: {\n    \".\u002Fbootstrap\": \".\u002Fsrc\u002Fbootstrap\",\n  },\n  shared: {\n    react: { singleton: true, requiredVersion: \"^18.0.0\" },\n    \"react-dom\": { singleton: true },\n  },\n});\n",[41,1957,1958,1968,1983,1999,2008,2028,2032,2040,2068,2088,2092],{"__ignoreMap":59},[75,1959,1960,1962,1964,1966],{"class":77,"line":78},[75,1961,1787],{"class":103},[75,1963,1790],{"class":107},[75,1965,112],{"class":111},[75,1967,450],{"class":92},[75,1969,1970,1972,1974,1976,1979,1981],{"class":77,"line":85},[75,1971,1799],{"class":191},[75,1973,195],{"class":92},[75,1975,198],{"class":115},[75,1977,1978],{"class":119},"app1",[75,1980,116],{"class":115},[75,1982,206],{"class":92},[75,1984,1985,1988,1990,1992,1995,1997],{"class":77,"line":130},[75,1986,1987],{"class":191},"  filename",[75,1989,195],{"class":92},[75,1991,198],{"class":115},[75,1993,1994],{"class":119},"remoteEntry.js",[75,1996,116],{"class":115},[75,1998,206],{"class":92},[75,2000,2001,2004,2006],{"class":77,"line":155},[75,2002,2003],{"class":191},"  exposes",[75,2005,195],{"class":92},[75,2007,185],{"class":92},[75,2009,2010,2012,2015,2017,2019,2021,2024,2026],{"class":77,"line":162},[75,2011,1910],{"class":115},[75,2013,2014],{"class":607},".\u002Fbootstrap",[75,2016,116],{"class":115},[75,2018,195],{"class":92},[75,2020,198],{"class":115},[75,2022,2023],{"class":119},".\u002Fsrc\u002Fbootstrap",[75,2025,116],{"class":115},[75,2027,206],{"class":92},[75,2029,2030],{"class":77,"line":188},[75,2031,876],{"class":92},[75,2033,2034,2036,2038],{"class":77,"line":209},[75,2035,1860],{"class":191},[75,2037,195],{"class":92},[75,2039,185],{"class":92},[75,2041,2042,2044,2046,2048,2050,2052,2054,2056,2058,2060,2062,2064,2066],{"class":77,"line":226},[75,2043,1869],{"class":191},[75,2045,195],{"class":92},[75,2047,93],{"class":92},[75,2049,1876],{"class":191},[75,2051,195],{"class":92},[75,2053,242],{"class":241},[75,2055,182],{"class":92},[75,2057,1894],{"class":191},[75,2059,195],{"class":92},[75,2061,198],{"class":115},[75,2063,1901],{"class":119},[75,2065,116],{"class":115},[75,2067,256],{"class":92},[75,2069,2070,2072,2074,2076,2078,2080,2082,2084,2086],{"class":77,"line":259},[75,2071,1910],{"class":115},[75,2073,1913],{"class":607},[75,2075,116],{"class":115},[75,2077,195],{"class":92},[75,2079,93],{"class":92},[75,2081,1876],{"class":191},[75,2083,195],{"class":92},[75,2085,242],{"class":241},[75,2087,256],{"class":92},[75,2089,2090],{"class":77,"line":653},[75,2091,876],{"class":92},[75,2093,2094,2096,2098],{"class":77,"line":661},[75,2095,262],{"class":92},[75,2097,124],{"class":111},[75,2099,127],{"class":92},[46,2101,2103],{"id":2102},"_2-集成-single-spa","2. 集成 single-spa",[963,2105,2106,2113],{},[966,2107,2108,2109,2112],{},"每个子应用需要导出 ",[41,2110,2111],{},"bootstrap"," 函数，并注册到 single-spa。",[966,2114,2115,2116,2119],{},"主应用使用 ",[41,2117,2118],{},"System"," 动态加载远程模块。",[23,2121,2122,1777],{},[1774,2123,2124],{},"子应用入口（bootstrap.js）",[51,2126,2128],{"className":69,"code":2127,"language":71,"meta":59,"style":59},"import React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport singleSpaReact from \"single-spa-react\";\nimport Root from \".\u002FRoot\";\n\nconst reactLifecycles = singleSpaReact({\n  React,\n  ReactDOM,\n  rootComponent: Root,\n  errorBoundary(err, info, props) {\n    return \u003Cdiv>Error\u003C\u002Fdiv>;\n  },\n});\n\nexport const { bootstrap, mount, unmount } = reactLifecycles;\n",[41,2129,2130,2150,2167,2185,2203,2207,2223,2230,2237,2249,2273,2298,2302,2310,2314],{"__ignoreMap":59},[75,2131,2132,2135,2138,2141,2143,2146,2148],{"class":77,"line":78},[75,2133,2134],{"class":564},"import",[75,2136,2137],{"class":111}," React ",[75,2139,2140],{"class":564},"from",[75,2142,198],{"class":115},[75,2144,2145],{"class":119},"react",[75,2147,116],{"class":115},[75,2149,127],{"class":92},[75,2151,2152,2154,2157,2159,2161,2163,2165],{"class":77,"line":85},[75,2153,2134],{"class":564},[75,2155,2156],{"class":111}," ReactDOM ",[75,2158,2140],{"class":564},[75,2160,198],{"class":115},[75,2162,1913],{"class":119},[75,2164,116],{"class":115},[75,2166,127],{"class":92},[75,2168,2169,2171,2174,2176,2178,2181,2183],{"class":77,"line":130},[75,2170,2134],{"class":564},[75,2172,2173],{"class":111}," singleSpaReact ",[75,2175,2140],{"class":564},[75,2177,198],{"class":115},[75,2179,2180],{"class":119},"single-spa-react",[75,2182,116],{"class":115},[75,2184,127],{"class":92},[75,2186,2187,2189,2192,2194,2196,2199,2201],{"class":77,"line":155},[75,2188,2134],{"class":564},[75,2190,2191],{"class":111}," Root ",[75,2193,2140],{"class":564},[75,2195,198],{"class":115},[75,2197,2198],{"class":119},".\u002FRoot",[75,2200,116],{"class":115},[75,2202,127],{"class":92},[75,2204,2205],{"class":77,"line":162},[75,2206,159],{"emptyLinePlaceholder":158},[75,2208,2209,2211,2214,2216,2219,2221],{"class":77,"line":188},[75,2210,89],{"class":88},[75,2212,2213],{"class":96}," reactLifecycles",[75,2215,104],{"class":103},[75,2217,2218],{"class":107}," singleSpaReact",[75,2220,112],{"class":111},[75,2222,450],{"class":92},[75,2224,2225,2228],{"class":77,"line":209},[75,2226,2227],{"class":111},"  React",[75,2229,206],{"class":92},[75,2231,2232,2235],{"class":77,"line":226},[75,2233,2234],{"class":111},"  ReactDOM",[75,2236,206],{"class":92},[75,2238,2239,2242,2244,2247],{"class":77,"line":259},[75,2240,2241],{"class":191},"  rootComponent",[75,2243,195],{"class":92},[75,2245,2246],{"class":111}," Root",[75,2248,206],{"class":92},[75,2250,2251,2255,2257,2259,2261,2264,2266,2269,2271],{"class":77,"line":653},[75,2252,2254],{"class":2253},"sVXei","  errorBoundary",[75,2256,112],{"class":92},[75,2258,1439],{"class":528},[75,2260,182],{"class":92},[75,2262,2263],{"class":528}," info",[75,2265,182],{"class":92},[75,2267,2268],{"class":528}," props",[75,2270,124],{"class":92},[75,2272,185],{"class":92},[75,2274,2275,2278,2281,2284,2287,2290,2293,2295],{"class":77,"line":661},[75,2276,2277],{"class":564},"    return",[75,2279,2280],{"class":92}," \u003C",[75,2282,2283],{"class":917},"div",[75,2285,2286],{"class":92},">",[75,2288,2289],{"class":111},"Error",[75,2291,2292],{"class":92},"\u003C\u002F",[75,2294,2283],{"class":917},[75,2296,2297],{"class":92},">;\n",[75,2299,2300],{"class":77,"line":671},[75,2301,876],{"class":92},[75,2303,2304,2306,2308],{"class":77,"line":679},[75,2305,262],{"class":92},[75,2307,124],{"class":111},[75,2309,127],{"class":92},[75,2311,2312],{"class":77,"line":685},[75,2313,159],{"emptyLinePlaceholder":158},[75,2315,2316,2319,2322,2324,2327,2329,2332,2334,2337,2339,2341,2343],{"class":77,"line":776},[75,2317,2318],{"class":564},"export",[75,2320,2321],{"class":88}," const",[75,2323,93],{"class":92},[75,2325,2326],{"class":96}," bootstrap",[75,2328,182],{"class":92},[75,2330,2331],{"class":96}," mount",[75,2333,182],{"class":92},[75,2335,2336],{"class":96}," unmount",[75,2338,100],{"class":92},[75,2340,104],{"class":103},[75,2342,2213],{"class":111},[75,2344,127],{"class":92},[23,2346,2347,1777],{},[1774,2348,2349],{},"主应用注册子应用",[51,2351,2353],{"className":69,"code":2352,"language":71,"meta":59,"style":59},"import { registerApplication, start } from \"single-spa\";\n\nregisterApplication({\n  name: \"@org\u002Fapp1\",\n  app: () => import(\"app1\u002Fbootstrap\"), \u002F\u002F 来自 Module Federation remote\n  activeWhen: [\"\u002Fapp1\"],\n});\n\nstart();\n",[41,2354,2355,2383,2387,2396,2411,2442,2464,2472,2476],{"__ignoreMap":59},[75,2356,2357,2359,2361,2364,2366,2369,2371,2374,2376,2379,2381],{"class":77,"line":78},[75,2358,2134],{"class":564},[75,2360,93],{"class":92},[75,2362,2363],{"class":111}," registerApplication",[75,2365,182],{"class":92},[75,2367,2368],{"class":111}," start",[75,2370,100],{"class":92},[75,2372,2373],{"class":564}," from",[75,2375,198],{"class":115},[75,2377,2378],{"class":119},"single-spa",[75,2380,116],{"class":115},[75,2382,127],{"class":92},[75,2384,2385],{"class":77,"line":85},[75,2386,159],{"emptyLinePlaceholder":158},[75,2388,2389,2392,2394],{"class":77,"line":130},[75,2390,2391],{"class":107},"registerApplication",[75,2393,112],{"class":111},[75,2395,450],{"class":92},[75,2397,2398,2400,2402,2404,2407,2409],{"class":77,"line":155},[75,2399,1799],{"class":191},[75,2401,195],{"class":92},[75,2403,198],{"class":115},[75,2405,2406],{"class":119},"@org\u002Fapp1",[75,2408,116],{"class":115},[75,2410,206],{"class":92},[75,2412,2413,2416,2418,2421,2423,2426,2428,2430,2433,2435,2437,2439],{"class":77,"line":162},[75,2414,2415],{"class":107},"  app",[75,2417,195],{"class":92},[75,2419,2420],{"class":92}," ()",[75,2422,538],{"class":88},[75,2424,2425],{"class":103}," import",[75,2427,112],{"class":111},[75,2429,116],{"class":115},[75,2431,2432],{"class":119},"app1\u002Fbootstrap",[75,2434,116],{"class":115},[75,2436,124],{"class":111},[75,2438,182],{"class":92},[75,2440,2441],{"class":81}," \u002F\u002F 来自 Module Federation remote\n",[75,2443,2444,2447,2449,2452,2454,2457,2459,2462],{"class":77,"line":188},[75,2445,2446],{"class":191},"  activeWhen",[75,2448,195],{"class":92},[75,2450,2451],{"class":111}," [",[75,2453,116],{"class":115},[75,2455,2456],{"class":119},"\u002Fapp1",[75,2458,116],{"class":115},[75,2460,2461],{"class":111},"]",[75,2463,206],{"class":92},[75,2465,2466,2468,2470],{"class":77,"line":209},[75,2467,262],{"class":92},[75,2469,124],{"class":111},[75,2471,127],{"class":92},[75,2473,2474],{"class":77,"line":226},[75,2475,159],{"emptyLinePlaceholder":158},[75,2477,2478,2480,2482],{"class":77,"line":259},[75,2479,1291],{"class":107},[75,2481,1201],{"class":111},[75,2483,127],{"class":92},[46,2485,2487],{"id":2486},"_3-共享依赖策略与版本冲突","3. 共享依赖策略与版本冲突",[963,2489,2490,2496,2506],{},[966,2491,968,2492,2495],{},[41,2493,2494],{},"singleton: true"," 确保 React 等库只加载一次。",[966,2497,968,2498,2501,2502,2505],{},[41,2499,2500],{},"requiredVersion"," 声明兼容版本范围，Webpack 会在加载时检查主从版本是否匹配，不匹配时会在控制台 warning 但继续执行（可选择 ",[41,2503,2504],{},"eager: true"," 强制主应用提供）。",[966,2507,2508,2509,2512],{},"对于非核心库（如 lodash），可以设置 ",[41,2510,2511],{},"singleton: false","，允许主子应用各自加载独立版本，避免版本冲突。",[46,2514,2516],{"id":2515},"_4-构建与部署","4. 构建与部署",[963,2518,2519,2525,2528],{},[966,2520,2521,2522,2524],{},"每个子应用独立构建，输出 ",[41,2523,1994],{}," 及各自的 chunk。",[966,2526,2527],{},"主应用构建时不需要知道子应用的具体代码，只需远程入口地址（可在运行时动态注入）。",[966,2529,2530,2531,2533],{},"生产环境可将子应用的 ",[41,2532,1994],{}," 上传到 CDN，主应用通过环境变量读取地址。",[2535,2536,2537],"h2",{"id":2537},"总结",[2539,2540,2541,2557],"table",{},[2542,2543,2544],"thead",{},[2545,2546,2547,2551,2554],"tr",{},[2548,2549,2550],"th",{},"实践方向",[2548,2552,2553],{},"关键技术",[2548,2555,2556],{},"收益",[2558,2559,2560,2578,2591,2606],"tbody",{},[2545,2561,2562,2568,2575],{},[2563,2564,2565],"td",{},[1774,2566,2567],{},"多环境配置",[2563,2569,2570,2572,2573],{},[41,2571,43],{}," + ",[41,2574,417],{},[2563,2576,2577],{},"配置复用、环境隔离",[2545,2579,2580,2585,2588],{},[2563,2581,2582],{},[1774,2583,2584],{},"Docker 化构建",[2563,2586,2587],{},"多阶段构建、Webpack 持久化缓存、volume 缓存",[2563,2589,2590],{},"环境一致、CI 提速",[2545,2592,2593,2598,2603],{},[2563,2594,2595],{},[1774,2596,2597],{},"自定义 CLI",[2563,2599,2600,2602],{},[41,2601,1007],{}," + Webpack Node API",[2563,2604,2605],{},"统一团队构建命令，可定制",[2545,2607,2608,2613,2616],{},[2563,2609,2610],{},[1774,2611,2612],{},"微前端集成",[2563,2614,2615],{},"Module Federation + single-spa",[2563,2617,2618],{},"独立部署、技术栈无关、依赖共享",[23,2620,2621],{},"具体方案须结合团队基础设施与发布流程评估，不宜照搬配置。",[2535,2623,2624],{"id":2624},"参考文献",[23,2626,2627],{},"以下链接在编写时均可正常访问：",[2539,2629,2630,2640],{},[2542,2631,2632],{},[2545,2633,2634,2637],{},[2548,2635,2636],{},"资料",[2548,2638,2639],{},"说明",[2558,2641,2642,2654,2666],{},[2545,2643,2644,2651],{},[2563,2645,2646],{},[27,2647,43],{"href":2648,"rel":2649},"https:\u002F\u002Fgithub.com\u002Fsurvivejs\u002Fwebpack-merge",[2650],"nofollow",[2563,2652,2653],{},"配置合并",[2545,2655,2656,2663],{},[2563,2657,2658],{},[27,2659,2662],{"href":2660,"rel":2661},"https:\u002F\u002Fwebpack.js.org\u002Fconcepts\u002Fmodule-federation\u002F",[2650],"Module Federation",[2563,2664,2665],{},"微前端",[2545,2667,2668,2674],{},[2563,2669,2670],{},[27,2671,2378],{"href":2672,"rel":2673},"https:\u002F\u002Fsingle-spa.js.org\u002F",[2650],[2563,2675,2676],{},"微前端编排",[2678,2679,2680],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sZUrc, html code.shiki .sZUrc{--shiki-light:#E53935;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":59,"searchDepth":85,"depth":85,"links":2682},[2683,2684,2685,2686,2687,2688],{"id":35,"depth":130,"text":36},{"id":691,"depth":130,"text":692},{"id":997,"depth":130,"text":998},{"id":1762,"depth":130,"text":1763},{"id":2537,"depth":85,"text":2537},{"id":2624,"depth":85,"text":2624},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fproject\u002FWebpack\u002Fcompany","knowledge\u002Fknowledge\u002Fbooklet\u002Fproject\u002FWebpack\u002Fcompany.md","md",{"items":2694},[2695,2699,2703,2707,2711,2715],{"path":2696,"title":2697,"description":2698,"category":10,"score":188},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fworkflow","工作原理","Webpack 是静态模块打包器：从入口递归解析依赖，经 Loader 转换后输出一个或多个 bundle。与 Vite 对比见 Webpack 与 Vite。",{"path":2700,"title":2701,"description":2702,"category":10,"score":188},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fchunks","产物优化","Webpack 通过代码分割、Tree Shaking、压缩与资源模块等减少体积、改善缓存。原理背景见 工作原理。",{"path":2704,"title":2705,"description":2706,"category":10,"score":188},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Floader","Loader","Loader 在 Webpack 构建链中把源文件转为可打包的 JS 模块（如 TS、SCSS、Vue SFC）。见 工作原理。",{"path":2708,"title":2709,"description":2710,"category":10,"score":188},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fadvanced","进阶配置","Webpack 进阶场景：多页面（MPA）、devServer、环境变量注入、Source Map、Module Federation 等。基础见 工作原理。",{"path":2712,"title":2713,"description":2714,"category":10,"score":188},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fwebpack\u002Fplugin","Plugin","Webpack 插件在构建生命周期钩子上扩展能力（修改资源、生成 HTML、上传 CDN 等）。背景见 工作原理；与 Loader 分工：Loader 转换单文件，插件面向整体构建。",{"path":2716,"title":2717,"description":2718,"category":10,"score":155},"\u002Fknowledge\u002Fbooklet\u002Fproject\u002Fproject\u002Fother","其他配置","除 ESLint、Prettier 等规范文件外，仓库中常见的工具链与包管理配置如下。见 工程化概览。",{"series":2720,"title":12,"items":2721,"index":85,"prev":2733,"next":2734},"booklet\u002Fproject\u002Fwebpack",[2722,2724,2726,2727,2729,2731],{"path":2708,"title":2709,"date":2723,"pinned":15},"2021-10-18",{"path":2700,"title":2701,"date":2725,"pinned":15},"2025-01-28",{"path":7,"title":8,"date":14,"pinned":15},{"path":2704,"title":2705,"date":2728,"pinned":15},"2022-11-14",{"path":2712,"title":2713,"date":2730,"pinned":15},"2020-08-27",{"path":2696,"title":2697,"date":2732,"pinned":15},"2025-12-19",{"path":2700,"title":2701,"date":2725,"pinned":15},{"path":2704,"title":2705,"date":2728,"pinned":15}]