Skip to content

Commit 2f9498e

Browse files
authored
[7.x backport] feat: read standalone targets from data-targets (#17725)
1 parent f3a2226 commit 2f9498e

2 files changed

Lines changed: 48 additions & 9 deletions

File tree

‎packages/babel-standalone/src/transformScriptTags.ts‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import type { InputOptions } from "@babel/core";
1414
let headEl: HTMLHeadElement;
1515
let inlineScriptCount = 0;
1616

17+
type Browsers = string | readonly string[];
18+
1719
type CompilationResult = {
1820
async: boolean;
1921
type: string;
@@ -26,6 +28,7 @@ type CompilationResult = {
2628
// todo: refine plugins/presets
2729
plugins: InputOptions["plugins"];
2830
presets: InputOptions["presets"];
31+
targets: Browsers;
2932
url: string | null;
3033
};
3134

@@ -54,7 +57,10 @@ function transformCode(
5457
* Builds the Babel options for transforming the specified script, using some
5558
* sensible default presets and plugins if none were explicitly provided.
5659
*/
57-
function buildBabelOptions(script: CompilationResult, filename: string) {
60+
function buildBabelOptions(
61+
script: CompilationResult,
62+
filename: string,
63+
): InputOptions {
5864
let presets = script.presets;
5965
if (!presets) {
6066
if (script.type === "module") {
@@ -63,9 +69,6 @@ function buildBabelOptions(script: CompilationResult, filename: string) {
6369
[
6470
"env",
6571
{
66-
targets: {
67-
esmodules: true,
68-
},
6972
modules: false,
7073
},
7174
],
@@ -84,12 +87,21 @@ function buildBabelOptions(script: CompilationResult, filename: string) {
8487
];
8588
}
8689

90+
const targets: InputOptions["targets"] = {
91+
browsers: script.targets,
92+
};
93+
94+
if (script.type === "module") {
95+
targets.esmodules = "intersect";
96+
}
97+
8798
return {
8899
filename,
89100
presets,
90101
plugins,
91102
sourceMaps: "inline" as const,
92103
sourceFileName: filename,
104+
targets,
93105
};
94106
}
95107

@@ -141,9 +153,9 @@ function load(
141153
/**
142154
* Converts a comma-separated data attribute string into an array of values. If
143155
* the string is empty, returns an empty array. If the string is not defined,
144-
* returns null.
156+
* returns undefined.
145157
*/
146-
function getPluginsOrPresetsFromScript(
158+
function parseFromScriptAttribute(
147159
script: HTMLScriptElement,
148160
attributeName: string,
149161
) {
@@ -155,7 +167,7 @@ function getPluginsOrPresetsFromScript(
155167
if (!rawValue) {
156168
// Any other falsy value (null, undefined) means we're not overriding this
157169
// setting, and should use the default.
158-
return null;
170+
return undefined;
159171
}
160172
return rawValue.split(",").map(item => item.trim());
161173
}
@@ -194,8 +206,9 @@ function loadScripts(
194206
nonce: script.nonce,
195207
error: false,
196208
executed: false,
197-
plugins: getPluginsOrPresetsFromScript(script, "data-plugins"),
198-
presets: getPluginsOrPresetsFromScript(script, "data-presets"),
209+
plugins: parseFromScriptAttribute(script, "data-plugins"),
210+
presets: parseFromScriptAttribute(script, "data-presets"),
211+
targets: parseFromScriptAttribute(script, "data-targets"),
199212
loaded: false,
200213
url: null,
201214
content: null,

‎packages/babel-standalone/test/transform-script-tags.test.js‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,30 @@ describeGte("16.0.0")("transformScriptTags", () => {
5454
});
5555
});
5656
});
57+
it("should support data-targets attribute", () => {
58+
const input = `globalThis ?? window; /\\p{ASCII}/v`;
59+
const targets = "chrome 84"; // Chrome 84 supports nullish coalescing but not the `v` flag in regexps.
60+
const dom = new JSDOM(
61+
`<!DOCTYPE html><head><script>${standaloneSource}</script><script type="text/babel" data-targets="${targets}">${input}</script></head>`,
62+
{ runScripts: "dangerously" },
63+
);
64+
return new Promise((resolve, reject) => {
65+
dom.window.addEventListener("DOMContentLoaded", () => {
66+
try {
67+
const transformedScriptElement =
68+
dom.window.document.head.children.item(2);
69+
expect(
70+
transformedScriptElement.getAttribute("data-targets"),
71+
).toBeNull();
72+
expect(transformedScriptElement.innerHTML).toContain(
73+
`globalThis ?? window;
74+
/\\p{ASCII}/u;`,
75+
);
76+
resolve();
77+
} catch (err) {
78+
reject(err);
79+
}
80+
});
81+
});
82+
});
5783
});

0 commit comments

Comments
 (0)