UNPKG

@modern-js/builder

Version:
237 lines (236 loc) • 9.37 kB
"use strict"; 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); var html_exports = {}; __export(html_exports, { applyInjectTags: () => applyInjectTags, builderPluginHtml: () => builderPluginHtml }); module.exports = __toCommonJS(html_exports); var import_path = __toESM(require("path")); var import_builder_shared = require("@modern-js/builder-shared"); var import_lodash = __toESM(require("@modern-js/utils/lodash")); async function getTemplateParameters(entryName, config, assetPrefix) { const { applyOptionsChain } = await Promise.resolve().then(() => __toESM(require("@modern-js/utils"))); const { mountId, templateParameters, templateParametersByEntries } = config.html; const meta = await (0, import_builder_shared.getMetaTags)(entryName, config); const title = (0, import_builder_shared.getTitle)(entryName, config); const templateParams = (templateParametersByEntries === null || templateParametersByEntries === void 0 ? void 0 : templateParametersByEntries[entryName]) || templateParameters; const baseParameters = { meta, title, mountId, entryName, assetPrefix }; return (compilation, assets, assetTags, pluginOptions) => { const defaultOptions = { compilation, webpackConfig: compilation.options, htmlWebpackPlugin: { tags: assetTags, files: assets, options: pluginOptions }, ...baseParameters }; return applyOptionsChain(defaultOptions, templateParams); }; } async function getChunks(entryName, entryValue) { const { isPlainObject } = await Promise.resolve().then(() => __toESM(require("@modern-js/utils"))); const dependOn = []; if (isPlainObject(entryValue)) { dependOn.push(...entryValue.dependOn); } return [ ...dependOn, entryName ]; } const applyInjectTags = (api) => { api.modifyBundlerChain(async (chain, { HtmlPlugin, CHAIN_ID }) => { const config = api.getNormalizedConfig(); const tags = import_lodash.default.castArray(config.html.tags).filter(Boolean); const tagsByEntries = import_lodash.default.mapValues(config.html.tagsByEntries, (tags2) => import_lodash.default.castArray(tags2).filter(Boolean)); const shouldByEntries = import_lodash.default.some(tagsByEntries, "length"); if (!tags.length && !shouldByEntries) { return; } const { HtmlTagsPlugin } = await Promise.resolve().then(() => __toESM(require("@modern-js/builder-shared"))); const sharedOptions = { HtmlPlugin, append: true, hash: false, publicPath: true, tags }; if (tags.length && !shouldByEntries) { chain.plugin(CHAIN_ID.PLUGIN.HTML_TAGS).use(HtmlTagsPlugin, [ sharedOptions ]); return; } for (const [entry, filename] of Object.entries(api.getHTMLPaths())) { const opts = { ...sharedOptions, includes: [ filename ] }; entry in tagsByEntries && (opts.tags = tagsByEntries[entry]); chain.plugin(`${CHAIN_ID.PLUGIN.HTML_TAGS}#${entry}`).use(HtmlTagsPlugin, [ opts ]); } }); }; const builderPluginHtml = () => ({ name: "builder-plugin-html", setup(api) { const routesInfo = []; api.modifyBundlerChain(async (chain, { HtmlPlugin, isProd, CHAIN_ID, target }) => { const config = api.getNormalizedConfig(); if ((0, import_builder_shared.isHtmlDisabled)(config, target)) { return; } const { removeTailSlash, applyOptionsChain } = await Promise.resolve().then(() => __toESM(require("@modern-js/utils"))); const minify = await (0, import_builder_shared.getMinify)(isProd, config); const assetPrefix = removeTailSlash(chain.output.get("publicPath") || ""); const entries = chain.entryPoints.entries() || {}; const entryNames = Object.keys(entries); const htmlPaths = api.getHTMLPaths(); const faviconUrls = []; await Promise.all(entryNames.map(async (entryName, index) => { const entryValue = entries[entryName].values(); const chunks = await getChunks(entryName, entryValue); const inject = (0, import_builder_shared.getInject)(entryName, config); const favicon = (0, import_builder_shared.getFavicon)(entryName, config); const filename = htmlPaths[entryName]; const template = (0, import_builder_shared.getTemplatePath)(entryName, config); const templateParameters = await getTemplateParameters(entryName, config, assetPrefix); const pluginOptions = { chunks, inject, minify, filename, template, templateParameters, scriptLoading: config.html.scriptLoading }; if (favicon) { if ((0, import_builder_shared.isURL)(favicon)) { faviconUrls.push({ filename, url: favicon }); } else { pluginOptions.favicon = favicon; } } const finalOptions = applyOptionsChain(pluginOptions, config.tools.htmlPlugin, { entryName, entryValue }); routesInfo.push({ urlPath: index === 0 ? "/" : `/${entryName}`, entryName, entryPath: filename, isSPA: true }); chain.plugin(`${CHAIN_ID.PLUGIN.HTML}-${entryName}`).use(HtmlPlugin, [ finalOptions ]); })); if (config.security) { const { nonce } = config.security; if (nonce) { const { HtmlNoncePlugin } = await Promise.resolve().then(() => __toESM(require("@modern-js/builder-shared"))); chain.plugin(CHAIN_ID.PLUGIN.HTML_NONCE).use(HtmlNoncePlugin, [ { nonce, HtmlPlugin } ]); } } if (config.html) { const { appIcon, crossorigin } = config.html; if (crossorigin) { const { HtmlCrossOriginPlugin } = await Promise.resolve().then(() => __toESM(require("@modern-js/builder-shared"))); const formattedCrossorigin = crossorigin === true ? "anonymous" : crossorigin; chain.plugin(CHAIN_ID.PLUGIN.HTML_CROSS_ORIGIN).use(HtmlCrossOriginPlugin, [ { crossOrigin: formattedCrossorigin, HtmlPlugin } ]); chain.output.crossOriginLoading(formattedCrossorigin); } if (faviconUrls.length) { const { HtmlFaviconUrlPlugin } = await Promise.resolve().then(() => __toESM(require("@modern-js/builder-shared"))); chain.plugin(CHAIN_ID.PLUGIN.FAVICON_URL).use(HtmlFaviconUrlPlugin, [ { faviconUrls, HtmlPlugin } ]); } if (appIcon) { const { HtmlAppIconPlugin } = await Promise.resolve().then(() => __toESM(require("@modern-js/builder-shared"))); const distDir = (0, import_builder_shared.getDistPath)(config.output, "image"); const iconPath = import_path.default.isAbsolute(appIcon) ? appIcon : import_path.default.join(api.context.rootPath, appIcon); chain.plugin(CHAIN_ID.PLUGIN.APP_ICON).use(HtmlAppIconPlugin, [ { iconPath, distDir, HtmlPlugin } ]); } } }); const emitRouteJson = async () => { const { fs, ROUTE_SPEC_FILE } = await Promise.resolve().then(() => __toESM(require("@modern-js/utils"))); const routeFilePath = import_path.default.join(api.context.distPath, ROUTE_SPEC_FILE); if (!await (0, import_builder_shared.isFileExists)(routeFilePath) && routesInfo.length) { await fs.outputFile(routeFilePath, JSON.stringify({ routes: routesInfo }, null, 2)); } }; api.onBeforeBuild(emitRouteJson); api.onBeforeStartDevServer(emitRouteJson); applyInjectTags(api); } }); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { applyInjectTags, builderPluginHtml });