@modern-js/builder
Version:
Builder of modern.js.
237 lines (236 loc) • 9.37 kB
JavaScript
;
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
});