UNPKG

@umijs/plugins

Version:
361 lines (357 loc) 13.5 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/qiankun/slave.ts var slave_exports = {}; __export(slave_exports, { default: () => slave_default }); module.exports = __toCommonJS(slave_exports); var import_http_proxy_middleware = require("@umijs/bundler-utils/compiled/http-proxy-middleware"); var import_utils = require("@umijs/utils"); var import_assert = __toESM(require("assert")); var import_fs = require("fs"); var import_path = require("path"); var import_umi = require("umi"); var import_plugin_utils = require("umi/plugin-utils"); var import_withTmpPath = require("../utils/withTmpPath"); var import_constants = require("./constants"); function getCurrentLocalDevServerEntry(api, req) { const port = api.appData.port; const hostname = req.hostname; const protocol = req.protocol; return `${protocol}://${hostname}${port ? ":" : ""}${port}/local-dev-server`; } function handleOriginalHtml(api, microAppEntry, originalHtml) { var _a, _b; const appName = ((_b = (_a = api.config.qiankun) == null ? void 0 : _a.slave) == null ? void 0 : _b.appName) || api.pkg.name; (0, import_assert.default)( appName, "[@umijs/plugin-qiankun]: You should have name in package.json" ); const $ = import_utils.cheerio.load(originalHtml); $("head").prepend( `<script>window.__QIANKUN_DEVELOPMENT__=true</script> <script type="extra-qiankun-config">${JSON.stringify({ master: { apps: [ { name: appName, entry: microAppEntry, extraSource: microAppEntry } ], routes: [ { microApp: appName, name: appName, path: "/" + appName, extraSource: microAppEntry } ], prefetch: false } })}</script>` ); return api.applyPlugins({ key: "modifyMasterHTML", type: api.ApplyPluginsType.modify, initialValue: $.html() }); } function isSlaveEnable(opts) { var _a, _b; const slaveCfg = (_b = (_a = opts.userConfig) == null ? void 0 : _a.qiankun) == null ? void 0 : _b.slave; if (slaveCfg) { return slaveCfg.enable !== false; } return !!process.env.INITIAL_QIANKUN_SLAVE_OPTIONS; } var slave_default = (api) => { api.describe({ key: "qiankun-slave", enableBy: isSlaveEnable }); api.addRuntimePlugin(() => { return [(0, import_withTmpPath.withTmpPath)({ api, path: "slaveRuntimePlugin.ts" })]; }); api.register({ key: "addExtraModels", fn() { return [ (0, import_withTmpPath.withTmpPath)({ api, path: `qiankunModel.ts#{"namespace":"${import_constants.qiankunStateFromMasterModelNamespace}"}` }) ]; } }); api.onGenerateFiles(() => { api.writeTmpFile({ path: import_umi.RUNTIME_TYPE_FILE_NAME, content: ` interface LifeCycles { bootstrap?: (props?: any) => Promise<any>; mount?: (props?: any) => Promise<any>; unmount?: (props?: any) => Promise<any>; update?: (props?: any) => Promise<any>; } type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }; type XOR<T, U> = (Without<T, U> & U) | (Without<U, T> & T); interface SlaveOption extends LifeCycles { enable?: boolean; } interface Config { slave?: SlaveOption; } export interface IRuntimeConfig { qiankun?: XOR<Config, LifeCycles> } ` }); }); api.modifyDefaultConfig((memo) => { var _a, _b, _c, _d, _e; const initialSlaveOptions = { devSourceMap: true, ...JSON.parse(process.env.INITIAL_QIANKUN_SLAVE_OPTIONS || "{}"), ...(memo.qiankun || {}).slave }; const modifiedDefaultConfig = { ...memo, // 默认开启 runtimePublicPath,避免出现 dynamic import 场景子应用资源地址出问题 runtimePublicPath: true, qiankun: { ...memo.qiankun, slave: initialSlaveOptions } }; const shouldNotModifyDefaultBase = ((_b = (_a = api.userConfig.qiankun) == null ? void 0 : _a.slave) == null ? void 0 : _b.shouldNotModifyDefaultBase) ?? initialSlaveOptions.shouldNotModifyDefaultBase; const historyType = ((_c = api.userConfig.history) == null ? void 0 : _c.type) || "browser"; if (!shouldNotModifyDefaultBase && historyType !== "hash") { modifiedDefaultConfig.base = `/${api.pkg.name}`; } if (modifiedDefaultConfig.mfsu !== false) { modifiedDefaultConfig.mfsu = { ...modifiedDefaultConfig.mfsu, mfName: ((_d = modifiedDefaultConfig.mfsu) == null ? void 0 : _d.mfName) || `mf_${(_e = api.pkg.name) == null ? void 0 : _e.replace(/^@/, "").replace(/\W/g, "_")}` }; } return modifiedDefaultConfig; }); api.addHTMLHeadScripts(() => { var _a, _b; const dontModify = (_b = (_a = api.config.qiankun) == null ? void 0 : _a.slave) == null ? void 0 : _b.shouldNotModifyRuntimePublicPath; return dontModify ? [] : [ `window.publicPath = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ || "${api.config.publicPath || "/"}";` ]; }); api.chainWebpack((config, { ssr }) => { if (ssr || api.userConfig.utoopack) { return; } (0, import_assert.default)(api.pkg.name, "You should have name in package.json."); const { shouldNotAddLibraryChunkName = api.env === "production" || !Boolean(api.config.mfsu) } = (api.config.qiankun || {}).slave; config.output.libraryTarget("umd").library( shouldNotAddLibraryChunkName ? api.pkg.name : `${api.pkg.name}-[name]` ); return config; }); api.modifyHTML(($) => { $("script").each((_, el) => { const scriptEl = $(el); const umiEntry = /\/?umi(\.\w+)?\.js$/g; if (umiEntry.test(scriptEl.attr("src") ?? "")) { scriptEl.attr("entry", ""); } }); return $; }); api.addEntryImports(() => { return [ { source: "@@/plugin-qiankun-slave/lifecycles", specifier: "{ genMount as qiankun_genMount, genBootstrap as qiankun_genBootstrap, genUnmount as qiankun_genUnmount, genUpdate as qiankun_genUpdate }" } ]; }); api.addEntryCode(() => { var _a, _b; const appName = ((_b = (_a = api.config.qiankun) == null ? void 0 : _a.slave) == null ? void 0 : _b.appName) || api.pkg.name; return [ ` const qiankun_noop = () => new Error('qiankun lifecycle is not available for server runtime!'); const isServer = typeof window === 'undefined'; export const bootstrap = isServer ? qiankun_noop: qiankun_genBootstrap(render); export const mount = isServer ? qiankun_noop : qiankun_genMount('${api.config.mountElementId}'); export const unmount = isServer ? qiankun_noop : qiankun_genUnmount('${api.config.mountElementId}'); export const update = isServer ? qiankun_noop : qiankun_genUpdate(); if (!isServer && ${Boolean(api.userConfig.utoopack)}) { window['${appName}'] = { bootstrap, mount, unmount, update, }; } // 增加 ssr 的判断 if (!isServer && !window.__POWERED_BY_QIANKUN__) { bootstrap().then(mount); } ` ]; }); function getFileContent(file) { return (0, import_fs.readFileSync)( (0, import_path.join)(__dirname, "../../libs/qiankun/slave", file), "utf-8" ); } api.onGenerateFiles({ fn() { [ "constants.ts", "qiankunModel.ts", "connectMaster.tsx", "MicroAppLink.tsx", "slaveRuntimePlugin.ts", "lifecycles.ts" ].forEach((file) => { api.writeTmpFile({ path: file.replace(/\.tpl$/, ""), content: getFileContent(file).replace( "__USE_MODEL__", api.isPluginEnable("model") ? `import { useModel } from '@@/plugin-model'` : `console.warn(\`[plugins/qiankun]: Seems like you're not using @umijs/plugin-model, you need to install it or some features may not work!\`); const useModel = null` ).replace( /from 'qiankun'/g, `from '${(0, import_plugin_utils.winPath)((0, import_path.dirname)(require.resolve("qiankun/package")))}'` ).replace( /from 'lodash\//g, `from '${(0, import_plugin_utils.winPath)((0, import_path.dirname)(require.resolve("lodash/package")))}/` ) }); }); api.writeTmpFile({ path: "index.ts", content: ` export { connectMaster } from './connectMaster'; export { MicroAppLink } from './MicroAppLink'; ` }); }, before: "model" }); api.addMiddlewares(async () => { return async (req, res, next) => { var _a; const qiankunConfig = api.config.qiankun || {}; const masterEntry = (_a = qiankunConfig.slave) == null ? void 0 : _a.masterEntry; const { proxyToMasterEnabled } = await api.applyPlugins({ key: "shouldProxyToMaster", type: api.ApplyPluginsType.modify, initialValue: { proxyToMasterEnabled: true, req } }) ?? {}; if (masterEntry && proxyToMasterEnabled) { await api.applyPlugins({ key: "onLocalProxyStart", type: api.ApplyPluginsType.event }); const modifyLocalProxyOpts = await api.applyPlugins({ key: "modifyLocalProxyOpts", type: api.ApplyPluginsType.modify, initialValue: {} }) ?? {}; const localProxyOpts = { target: masterEntry, secure: false, ignorePath: false, followRedirects: false, changeOrigin: true, selfHandleResponse: true, ...modifyLocalProxyOpts }; return (0, import_http_proxy_middleware.createProxyMiddleware)( (pathname) => pathname !== "/local-dev-server", { ...localProxyOpts, onProxyReq(proxyReq) { api.applyPlugins({ key: "onLocalProxyReq", type: api.ApplyPluginsType.event, sync: true, args: proxyReq }); }, onProxyRes: (0, import_http_proxy_middleware.responseInterceptor)( async (responseBuffer, proxyRes, req2, res2) => { var _a2; if (proxyRes.statusCode === 302) { const { ignorePath = false } = localProxyOpts; const { hostname, url, protocol } = req2; const port = process.env.PORT || ((_a2 = api.appData) == null ? void 0 : _a2.port); const gotoBasePart = `${protocol}://${hostname}:${port}${ignorePath && url ? url : "/"}`; const fromBasePart = masterEntry; const locationUrl = proxyRes.headers.location || ""; const [originAndPath, searchParams] = locationUrl.split("?"); const searchHandled = searchParams ? `?${searchParams.replace( encodeURIComponent(fromBasePart), encodeURIComponent(gotoBasePart) )}` : ""; const redirectUrl = `${originAndPath}${searchHandled}`; const redirectMessage = `[@umijs/plugin-qiankun]: redirect to ${redirectUrl}`; api.logger.info(redirectMessage); res2.statusCode = 302; res2.setHeader("location", redirectUrl); return redirectMessage; } const microAppEntry = getCurrentLocalDevServerEntry(api, req2); const originalHtml = responseBuffer.toString("utf8"); const html = handleOriginalHtml( api, microAppEntry, originalHtml ); return html; } ), onError(err, _, res2) { api.logger.error(err); res2.set("content-type", "text/plain; charset=UTF-8"); res2.end( `[@umijs/plugin-qiankun] 代理到 ${masterEntry} 时出错了,请尝试 ${masterEntry} 是否是可以正常访问的,然后重新启动项目试试。(注意如果出现跨域问题,请修改本地 host ,通过一个和主应用相同的一级域名的域名来访问 127.0.0.1)` ); } } )(req, res, next); } return next(); }; }); };