From e9fc7f78b457070ff9c273e8b463c64c9004aa8f Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 27 Oct 2022 09:29:22 +0800 Subject: [PATCH] Build: improve use of `define` option (#13728) --- scripts/build/build-javascript-module.js | 19 ++++++----- .../esbuild-plugins/primitive-define.mjs | 32 +++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 scripts/build/esbuild-plugins/primitive-define.mjs diff --git a/scripts/build/build-javascript-module.js b/scripts/build/build-javascript-module.js index 6099de50d..0e1112527 100644 --- a/scripts/build/build-javascript-module.js +++ b/scripts/build/build-javascript-module.js @@ -14,6 +14,7 @@ import esbuildPluginVisualizer from "./esbuild-plugins/visualizer.mjs"; import esbuildPluginStripNodeProtocol from "./esbuild-plugins/strip-node-protocol.mjs"; import esbuildPluginThrowWarnings from "./esbuild-plugins/throw-warnings.mjs"; import esbuildPluginShimCommonjsObjects from "./esbuild-plugins/shim-commonjs-objects.mjs"; +import esbuildPluginPrimitiveDefine from "./esbuild-plugins/primitive-define.mjs"; import transform from "./transform/index.js"; const { dirname, readJsonSync, require } = createEsmUtils(import.meta); @@ -96,8 +97,8 @@ function getEsbuildOptions({ file, files, shouldCollectLicenses, cliOptions }) { ]; const define = { - "process.env.PRETTIER_TARGET": JSON.stringify(file.platform), - "process.env.NODE_ENV": JSON.stringify("production"), + "process.env.PRETTIER_TARGET": file.platform, + "process.env.NODE_ENV": "production", }; if (file.platform === "universal") { @@ -109,15 +110,17 @@ function getEsbuildOptions({ file, files, shouldCollectLicenses, cliOptions }) { replacement: "globalThis.PRETTIER_DEBUG", }); - define.process = JSON.stringify({ env: {}, argv: [] }); + define.process = undefined; + // @babel/code-frame/lib/index.js + define["process.emitWarning"] = undefined; + // postcss/lib/postcss.js + define["process.env.LANG"] = ""; // Replace `__dirname` and `__filename` with a fake value // So `parser-typescript.js` won't contain a path of working directory // See #8268 - define.__filename = JSON.stringify( - "/prettier-security-filename-placeholder.js" - ); - define.__dirname = JSON.stringify("/prettier-security-dirname-placeholder"); + define.__filename = "/prettier-security-filename-placeholder.js"; + define.__dirname = "/prettier-security-dirname-placeholder"; } if (file.platform === "node") { @@ -198,10 +201,10 @@ function getEsbuildOptions({ file, files, shouldCollectLicenses, cliOptions }) { const esbuildOptions = { entryPoints: [path.join(PROJECT_ROOT, file.input)], - define, bundle: true, metafile: true, plugins: [ + esbuildPluginPrimitiveDefine(define), esbuildPluginEvaluate(), esbuildPluginStripNodeProtocol(), esbuildPluginReplaceModule({ diff --git a/scripts/build/esbuild-plugins/primitive-define.mjs b/scripts/build/esbuild-plugins/primitive-define.mjs new file mode 100644 index 000000000..41e447440 --- /dev/null +++ b/scripts/build/esbuild-plugins/primitive-define.mjs @@ -0,0 +1,32 @@ +function stringify(value) { + if ( + value !== null && + !["boolean", "number", "string", "undefined"].includes(typeof value) + ) { + throw Object.assign(new TypeError("value not allowed"), { value }); + } + + return JSON.stringify(value); +} + +/* +Non-primitive value will cause esbuild inject a function call in every file +only primitive values are allowed to use. +*/ +export default function esbuildPluginPrimitiveDefine(define) { + return { + name: "primitive-define", + setup(build) { + const esbuildConfig = build.initialOptions; + if (esbuildConfig.define) { + throw new Error( + "Use `esbuildPluginPrimitiveDefine(define)` instead of 'define' option" + ); + } + + esbuildConfig.define = Object.fromEntries( + Object.entries(define).map(([key, value]) => [key, stringify(value)]) + ); + }, + }; +}