Files
test-repo/scripts/build/bundler.mjs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

251 lines
7.4 KiB
JavaScript
Raw Normal View History

import fs from "node:fs/promises";
2021-05-15 20:09:52 +08:00
import path from "node:path";
import createEsmUtils from "esm-utils";
2021-05-27 08:54:42 +08:00
import builtinModules from "builtin-modules";
import browserslist from "browserslist";
import * as babel from "@babel/core";
import esbuild from "esbuild";
import { NodeModulesPolyfillPlugin as esbuildPluginNodeModulePolyfills } from "@esbuild-plugins/node-modules-polyfill";
import { NodeGlobalsPolyfillPlugin as esbuildPluginNodeGlobalsPolyfills } from "@esbuild-plugins/node-globals-polyfill";
import esbuildPluginTextReplace from "esbuild-plugin-text-replace";
import { resolveToEsbuildTarget } from "esbuild-plugin-browserslist";
2021-09-11 09:55:46 +08:00
import { PROJECT_ROOT, DIST_DIR } from "../utils/index.mjs";
import esbuildPluginEvaluate from "./esbuild-plugins/evaluate.mjs";
import esbuildPluginReplaceModule from "./esbuild-plugins/replace-module.mjs";
import esbuildPluginLicense from "./esbuild-plugins/license.mjs";
import esbuildPluginUmd from "./esbuild-plugins/umd.mjs";
2021-05-27 08:54:42 +08:00
import bundles from "./config.mjs";
2018-05-29 14:59:57 -03:00
2021-11-29 12:52:43 +08:00
const { __dirname, json } = createEsmUtils(import.meta);
const packageJson = json.loadSync("../../package.json");
2020-05-11 09:05:06 +08:00
const umdTarget = resolveToEsbuildTarget(
browserslist(packageJson.browserslist),
{ printUnknownTargets: false }
);
2018-05-29 14:59:57 -03:00
function getBabelConfig(bundle) {
const config = {
babelrc: false,
2021-05-12 08:11:43 +08:00
assumptions: {
setSpreadProperties: true,
},
sourceType: "unambiguous",
2018-06-21 10:29:42 +08:00
plugins: bundle.babelPlugins || [],
compact: false,
exclude: [/\/core-js\//],
2018-05-29 14:59:57 -03:00
};
const targets = { node: "10" };
2018-05-29 14:59:57 -03:00
if (bundle.target === "universal") {
targets.browsers = packageJson.browserslist;
2018-05-29 14:59:57 -03:00
}
config.presets = [
2020-01-10 09:21:44 +08:00
[
2021-05-12 08:11:43 +08:00
"@babel/preset-env",
2020-01-10 09:21:44 +08:00
{
targets,
exclude: [
"es.array.unscopables.flat",
"es.array.unscopables.flat-map",
"es.array.sort",
"es.promise",
"es.promise.finally",
"es.string.replace",
"es.symbol.description",
"es.typed-array.*",
"web.*",
],
2020-01-10 09:21:44 +08:00
modules: false,
useBuiltIns: "usage",
corejs: {
version: 3,
},
debug: false,
2020-01-10 09:21:44 +08:00
},
],
2018-05-29 14:59:57 -03:00
];
2021-05-12 08:11:43 +08:00
config.plugins.push([
"@babel/plugin-proposal-object-rest-spread",
{ useBuiltIns: true },
]);
2018-05-29 14:59:57 -03:00
return config;
}
function* getEsbuildOptions(bundle, options) {
2018-05-29 14:59:57 -03:00
const replaceStrings = {
"process.env.PRETTIER_TARGET": JSON.stringify(bundle.target),
"process.env.NODE_ENV": JSON.stringify("production"),
// `tslib` exports global variables
"createExporter(root": "createExporter({}",
2018-05-29 14:59:57 -03:00
};
if (bundle.target === "universal") {
// We can't reference `process` in UMD bundles and this is
// an undocumented "feature"
replaceStrings["process.env.PRETTIER_DEBUG"] = "global.PRETTIER_DEBUG";
// `rollup-plugin-node-globals` replace `__dirname` with the real dirname
// `parser-typescript.js` will contain a path of working directory
// See #8268
replaceStrings.__filename = JSON.stringify(
"/prettier-security-filename-placeholder.js"
);
replaceStrings.__dirname = JSON.stringify(
"/prettier-security-dirname-placeholder"
);
2018-05-29 14:59:57 -03:00
}
2020-05-11 09:05:06 +08:00
2021-05-27 08:54:42 +08:00
const replaceModule = {};
// Replace other bundled files
if (bundle.target === "node") {
// Replace package.json with dynamic `require("./package.json")`
replaceModule[path.join(PROJECT_ROOT, "package.json")] = "./package.json";
// Dynamic require bundled files
2021-05-27 08:54:42 +08:00
for (const item of bundles) {
if (item.input !== bundle.input) {
replaceModule[path.join(PROJECT_ROOT, item.input)] = `./${item.output}`;
}
}
} else {
// Universal bundle only use version info from package.json
// Replace package.json with `{version: "{VERSION}"}`
replaceModule[path.join(PROJECT_ROOT, "package.json")] = {
code: `module.exports = ${JSON.stringify({
version: packageJson.version,
})};`,
};
// Replace parser getters with `undefined`
for (const file of [
"src/language-css/parsers.js",
"src/language-graphql/parsers.js",
"src/language-handlebars/parsers.js",
"src/language-html/parsers.js",
"src/language-js/parse/parsers.js",
"src/language-markdown/parsers.js",
"src/language-yaml/parsers.js",
]) {
replaceModule[path.join(PROJECT_ROOT, file)] = { code: "" };
}
}
let shouldMinify = options.minify;
2021-11-27 18:47:02 +08:00
if (typeof shouldMinify !== "boolean") {
shouldMinify = bundle.minify !== false && bundle.target === "universal";
}
const esbuildOptions = {
entryPoints: [path.join(PROJECT_ROOT, bundle.input)],
bundle: true,
metafile: true,
plugins: [
bundle.target === "universal" && esbuildPluginNodeGlobalsPolyfills(),
bundle.target === "universal" && esbuildPluginNodeModulePolyfills(),
esbuildPluginEvaluate(),
esbuildPluginReplaceModule({ ...replaceModule, ...bundle.replaceModule }),
esbuildPluginTextReplace({
include: /\.[cm]?js$/,
// TODO[@fisker]: Use RegExp when possible
pattern: Object.entries({ ...replaceStrings, ...bundle.replace }),
}),
options.onLicenseFound &&
esbuildPluginLicense({
cwd: PROJECT_ROOT,
thirdParty: {
includePrivate: true,
output: options.onLicenseFound,
2018-06-13 17:23:33 -03:00
},
}),
].filter(Boolean),
minify: shouldMinify,
legalComments: "none",
external: [...(bundle.external || [])],
// Disable esbuild auto discover `tsconfig.json` file
tsconfig: path.join(__dirname, "empty-tsconfig.json"),
mainFields: ["main"],
target: ["node10"],
logLevel: "error",
2018-05-29 14:59:57 -03:00
};
2019-09-16 17:13:32 +08:00
if (bundle.target === "universal") {
esbuildOptions.target.push(...umdTarget);
2021-11-27 18:47:02 +08:00
yield {
...esbuildOptions,
outfile: path.join(DIST_DIR, bundle.output),
plugins: [
esbuildPluginUmd({ name: bundle.name }),
...esbuildOptions.plugins,
],
format: "umd",
};
if (!bundle.format && !options.playground) {
yield {
...esbuildOptions,
outfile: path.join(
DIST_DIR,
`esm/${bundle.output.replace(".js", ".mjs")}`
),
format: "esm",
};
}
2021-11-27 18:47:02 +08:00
} else {
esbuildOptions.external.push(
...builtinModules,
"./package.json*",
...bundles
.filter((item) => item.input !== bundle.input)
.map((item) => `./${item.output}*`)
);
2019-09-16 17:13:32 +08:00
yield {
...esbuildOptions,
outfile: path.join(DIST_DIR, bundle.output),
format: "cjs",
};
}
2018-05-29 14:59:57 -03:00
}
async function runBuild(bundle, esbuildOptions) {
const { format, plugins, outfile } = esbuildOptions;
await esbuild.build({
...esbuildOptions,
plugins: plugins.filter(({ name }) => name !== "umd"),
format: format === "umd" ? "cjs" : format,
minify: false,
});
const text = await fs.readFile(outfile);
const { code } = await babel.transformAsync(text, {
filename: outfile,
...getBabelConfig(bundle),
});
await fs.writeFile(outfile, code);
await esbuild.build({
...esbuildOptions,
plugins: plugins.filter(({ name }) => name === "umd"),
entryPoints: [outfile],
allowOverwrite: true,
2018-05-29 14:59:57 -03:00
});
}
async function createBundle(bundle, options) {
if (
options.playground &&
(bundle.target !== "universal" || bundle.output === "doc.js")
) {
2020-10-26 09:44:09 +08:00
return { skipped: true };
}
2019-06-08 03:58:05 +08:00
const esbuildOptions = getEsbuildOptions(bundle, options);
for (const options of esbuildOptions) {
await runBuild(bundle, options);
2018-05-29 14:59:57 -03:00
}
2018-06-18 15:16:40 -03:00
return { bundled: true };
2021-05-15 20:09:52 +08:00
}
export default createBundle;