@griffel/transform 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,34 @@
1
1
  # Change Log - @griffel/transform
2
2
 
3
- This log was last generated on Fri, 06 Mar 2026 08:15:28 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 11 Mar 2026 13:31:20 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 2.0.0
8
+
9
+ Wed, 11 Mar 2026 13:31:20 GMT
10
+
11
+ ### Major changes
12
+
13
+ - BREAKING: Replace @linaria/shaker with @griffel/transform-shaker. Remove babelOptions from TransformOptions. Remove StrictOptions type. (olfedias@microsoft.com)
14
+
15
+ ### Patches
16
+
17
+ - feat: add collectPerfIssues option to TransformOptions (olfedias@microsoft.com)
18
+ - fix: fix VM result index mapping in batchEvaluator (olfedias@microsoft.com)
19
+
20
+ ## 1.2.1
21
+
22
+ Fri, 06 Mar 2026 15:56:28 GMT
23
+
24
+ ### Patches
25
+
26
+ - refactor: remove cookModuleId from module evaluation (olfedias@microsoft.com)
27
+ - Bump @griffel/core to v1.20.1
28
+
7
29
  ## 1.2.0
8
30
 
9
- Fri, 06 Mar 2026 08:15:28 GMT
31
+ Fri, 06 Mar 2026 08:17:05 GMT
10
32
 
11
33
  ### Minor changes
12
34
 
@@ -1,12 +1,13 @@
1
1
  import { Program } from 'oxc-parser';
2
- import { StrictOptions, AstEvaluatorPlugin } from './types.mjs';
3
2
  import { StyleCall } from '../types.mjs';
3
+ import { TransformResolver } from './module.mjs';
4
+ import { AstEvaluatorPlugin, EvalRule } from './types.mjs';
4
5
  /**
5
6
  * Batch evaluates all style calls in a file for better performance.
6
7
  * Uses static evaluation first, then falls back to VM evaluation for complex expressions.
7
8
  * Optimizes VM evaluation by sharing module loading and parsing overhead.
8
9
  */
9
- export declare function batchEvaluator(sourceCode: string, filename: string, styleCalls: StyleCall[], babelOptions: NonNullable<StrictOptions['babelOptions']>, evaluationRules: NonNullable<StrictOptions['rules']>, programAst: Program, astEvaluationPlugins?: AstEvaluatorPlugin[]): {
10
+ export declare function batchEvaluator(sourceCode: string, filename: string, styleCalls: StyleCall[], evaluationRules: EvalRule[], resolveFilename: TransformResolver, programAst: Program, astEvaluationPlugins?: AstEvaluatorPlugin[]): {
10
11
  usedVMForEvaluation: boolean;
11
12
  evaluationResults: unknown[];
12
13
  };
@@ -1,18 +1,25 @@
1
- import { StrictOptions } from './types.mjs';
1
+ import { EvalRule } from './types.mjs';
2
+ export type TransformResolver = (id: string, options: {
3
+ filename: string;
4
+ paths: readonly string[];
5
+ }) => {
6
+ path: string;
7
+ builtin: boolean;
8
+ };
2
9
  export declare class Module {
3
10
  readonly id: string;
4
11
  readonly filename: string;
5
12
  readonly paths: readonly string[];
6
- options: StrictOptions;
13
+ rules: EvalRule[];
7
14
  imports: Map<string, string[]> | null;
8
15
  dependencies: string[] | null;
9
16
  transform: ((code: string, filename: string) => string) | null;
17
+ static readonly extensions: Set<string>;
10
18
  exports: unknown;
11
- extensions: string[];
19
+ private readonly resolveFilename;
12
20
  private debug;
13
21
  private debuggerDepth;
14
- constructor(filename: string, options: StrictOptions, debuggerDepth?: number);
15
- resolve: (rawId: string) => string;
22
+ constructor(filename: string, rules: EvalRule[], resolveFilename: TransformResolver, debuggerDepth?: number);
16
23
  require: ((id: string) => unknown) & {
17
24
  ensure: () => void;
18
25
  cache: Record<string, Module>;
@@ -21,9 +28,5 @@ export declare class Module {
21
28
  evaluate(text: string, only?: string[] | null): void;
22
29
  static invalidate: () => void;
23
30
  static invalidateEvalCache: () => void;
24
- static _resolveFilename: (id: string, options: {
25
- filename: string;
26
- paths: readonly string[];
27
- }) => string;
28
31
  static _nodeModulePaths: (filename: string) => string[];
29
32
  }
@@ -1,19 +1,19 @@
1
1
  import { Node, Program } from 'oxc-parser';
2
- export type Evaluator = (filename: string, options: StrictOptions, text: string, only: string[] | null) => [string, Map<string, string[]> | null];
2
+ export type EvaluatorResult = {
3
+ code: string;
4
+ imports: Map<string, string[]> | null;
5
+ moduleKind: 'esm' | 'cjs';
6
+ };
3
7
  export type EvalRule = {
4
8
  test?: RegExp | ((path: string) => boolean);
5
- action: Evaluator | 'ignore' | string;
6
- };
7
- export type StrictOptions = {
8
- displayName: boolean;
9
- evaluate: boolean;
10
- babelOptions: {
11
- plugins?: unknown[];
12
- presets?: unknown[];
13
- [key: string]: unknown;
14
- };
15
- rules: EvalRule[];
9
+ action: Evaluator | 'ignore';
16
10
  };
11
+ export type Evaluator = (filename: string, text: string, only: string[] | null) => EvaluatorResult;
12
+ export interface TransformPerfIssue {
13
+ type: 'cjs-module' | 'barrel-export-star';
14
+ /** The dependency file that caused the issue */
15
+ dependencyFilename: string;
16
+ }
17
17
  export interface EvaluationResult {
18
18
  confident: boolean;
19
19
  value?: unknown;
@@ -1,2 +1,3 @@
1
- import { EvaluationResult, StrictOptions } from './types.mjs';
2
- export declare function vmEvaluator(sourceCode: string, filename: string, expressionCode: string, babelOptions: NonNullable<StrictOptions['babelOptions']>, evaluationRules: NonNullable<StrictOptions['rules']>): EvaluationResult;
1
+ import { TransformResolver } from './module.mjs';
2
+ import { EvalRule, EvaluationResult } from './types.mjs';
3
+ export declare function vmEvaluator(sourceCode: string, filename: string, expressionCode: string, evaluationRules: EvalRule[], resolveFilename: TransformResolver): EvaluationResult;
package/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- export { default as shakerEvaluator } from '@linaria/shaker';
2
- export { Module } from './evaluation/module.mjs';
1
+ export { default as shakerEvaluator } from '@griffel/transform-shaker';
2
+ export { Module, type TransformResolver } from './evaluation/module.mjs';
3
3
  export * as EvalCache from './evaluation/evalCache.mjs';
4
4
  export { ASSET_TAG_OPEN, ASSET_TAG_CLOSE } from './constants.mjs';
5
- export type { Evaluator, EvalRule } from './evaluation/types.mjs';
5
+ export type { Evaluator, EvaluatorResult, EvalRule } from './evaluation/types.mjs';
6
6
  export { transformSync, type TransformOptions, type TransformResult } from './transformSync.mjs';
7
7
  export { DEOPT, type Deopt } from './evaluation/astEvaluator.mjs';
8
- export type { AstEvaluatorPlugin, AstEvaluatorContext } from './evaluation/types.mjs';
8
+ export type { AstEvaluatorPlugin, AstEvaluatorContext, TransformPerfIssue } from './evaluation/types.mjs';
9
9
  export { fluentTokensPlugin } from './evaluation/fluentTokensPlugin.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@griffel/transform",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "A package that performs build time transforms for Griffel",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,8 +16,8 @@
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "dependencies": {
19
- "@griffel/core": "^1.20.0",
20
- "@linaria/shaker": "^3.0.0-beta.22",
19
+ "@griffel/core": "^1.20.1",
20
+ "@griffel/transform-shaker": "^1.0.0",
21
21
  "debug": "^4.3.0",
22
22
  "magic-string": "^0.30.19",
23
23
  "oxc-parser": "^0.116.0",
package/transform.js CHANGED
@@ -1,17 +1,181 @@
1
- import _shaker from "@linaria/shaker";
2
- import { default as default2 } from "@linaria/shaker";
1
+ import shakerEvaluator from "@griffel/transform-shaker";
2
+ import { default as default2 } from "@griffel/transform-shaker";
3
3
  import fs from "node:fs";
4
4
  import NativeModule from "node:module";
5
- import path, { dirname, extname } from "node:path";
5
+ import path from "node:path";
6
6
  import vm from "node:vm";
7
7
  import createDebug from "debug";
8
+ import { parseSync } from "oxc-parser";
9
+ import MagicString from "magic-string";
8
10
  import { createHash } from "node:crypto";
9
- import { rawTransferSupported, parseSync } from "oxc-parser";
10
11
  import { ScopeTracker, walk } from "oxc-walker";
11
- import MagicString from "magic-string";
12
12
  import { resolveStaticStyleRules, resolveResetStyleRules, resolveStyleRulesForSlots, normalizeCSSBucketEntry } from "@griffel/core";
13
13
  const ASSET_TAG_OPEN = "<griffel-asset>";
14
14
  const ASSET_TAG_CLOSE = "</griffel-asset>";
15
+ const prop = (node, key) => node[key];
16
+ function extractDeclaredNames(node) {
17
+ switch (node.type) {
18
+ case "Identifier":
19
+ return [prop(node, "name")];
20
+ case "ObjectPattern":
21
+ return prop(node, "properties").flatMap((p) => {
22
+ if (p.type === "RestElement") {
23
+ return extractDeclaredNames(prop(p, "argument"));
24
+ }
25
+ return extractDeclaredNames(prop(p, "value"));
26
+ });
27
+ case "ArrayPattern":
28
+ return prop(node, "elements").filter(Boolean).flatMap((el) => extractDeclaredNames(el));
29
+ case "AssignmentPattern":
30
+ return extractDeclaredNames(prop(node, "left"));
31
+ default:
32
+ return [];
33
+ }
34
+ }
35
+ function convertESMtoCJS(code, filename) {
36
+ const parseResult = parseSync(filename, code);
37
+ if (parseResult.errors.length > 0) {
38
+ throw new Error(
39
+ `convertESMtoCJS: failed to parse "${filename}": ${parseResult.errors.map((e) => e.message).join(", ")}`
40
+ );
41
+ }
42
+ const program = parseResult.program;
43
+ let hasESM = false;
44
+ for (const node of program.body) {
45
+ if (node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" || node.type === "ExportAllDeclaration") {
46
+ hasESM = true;
47
+ break;
48
+ }
49
+ }
50
+ if (!hasESM) {
51
+ return code;
52
+ }
53
+ const ms = new MagicString(code);
54
+ for (const node of program.body) {
55
+ switch (node.type) {
56
+ case "ImportDeclaration": {
57
+ const source = prop(prop(node, "source"), "value");
58
+ const specifiers = prop(node, "specifiers");
59
+ if (specifiers.length === 0) {
60
+ ms.overwrite(node.start, node.end, `require(${JSON.stringify(source)});`);
61
+ } else {
62
+ let defaultName = null;
63
+ let namespaceName = null;
64
+ const namedImports = [];
65
+ for (const spec of specifiers) {
66
+ if (spec.type === "ImportDefaultSpecifier") {
67
+ defaultName = prop(prop(spec, "local"), "name");
68
+ } else if (spec.type === "ImportNamespaceSpecifier") {
69
+ namespaceName = prop(prop(spec, "local"), "name");
70
+ } else if (spec.type === "ImportSpecifier") {
71
+ const importedNode = prop(spec, "imported");
72
+ const imported = importedNode.type === "Identifier" ? prop(importedNode, "name") : prop(importedNode, "value");
73
+ const local = prop(prop(spec, "local"), "name");
74
+ if (imported === local) {
75
+ namedImports.push(imported);
76
+ } else {
77
+ namedImports.push(`${imported}: ${local}`);
78
+ }
79
+ }
80
+ }
81
+ const parts = [];
82
+ if (namespaceName) {
83
+ parts.push(`const ${namespaceName} = require(${JSON.stringify(source)});`);
84
+ } else if (defaultName && namedImports.length > 0) {
85
+ const tempVar = `_require$${defaultName}`;
86
+ parts.push(`const ${tempVar} = require(${JSON.stringify(source)});`);
87
+ parts.push(`const ${defaultName} = ${tempVar}.__esModule ? ${tempVar}.default : ${tempVar};`);
88
+ parts.push(`const { ${namedImports.join(", ")} } = ${tempVar};`);
89
+ } else if (defaultName) {
90
+ const tempVar = `_require$${defaultName}`;
91
+ parts.push(`const ${tempVar} = require(${JSON.stringify(source)});`);
92
+ parts.push(`const ${defaultName} = ${tempVar}.__esModule ? ${tempVar}.default : ${tempVar};`);
93
+ } else if (namedImports.length > 0) {
94
+ parts.push(`const { ${namedImports.join(", ")} } = require(${JSON.stringify(source)});`);
95
+ }
96
+ ms.overwrite(node.start, node.end, parts.join("\n"));
97
+ }
98
+ break;
99
+ }
100
+ case "ExportNamedDeclaration": {
101
+ const decl = prop(node, "declaration");
102
+ if (decl) {
103
+ ms.overwrite(node.start, decl.start, "");
104
+ if (decl.type === "VariableDeclaration") {
105
+ const names = prop(decl, "declarations").flatMap(
106
+ (d) => extractDeclaredNames(prop(d, "id"))
107
+ );
108
+ const exportsCode = names.map((name) => `exports.${name} = ${name};`).join(" ");
109
+ ms.appendLeft(node.end, "\n" + exportsCode);
110
+ } else if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") {
111
+ const id = prop(decl, "id");
112
+ if (id) {
113
+ const name = prop(id, "name");
114
+ ms.appendLeft(node.end, `
115
+ exports.${name} = ${name};`);
116
+ }
117
+ }
118
+ } else if (prop(node, "source")) {
119
+ const source = prop(prop(node, "source"), "value");
120
+ const parts = [];
121
+ for (const spec of prop(node, "specifiers")) {
122
+ const localNode = prop(spec, "local");
123
+ const exportedNode = prop(spec, "exported");
124
+ const local = localNode.type === "Identifier" ? prop(localNode, "name") : prop(localNode, "value");
125
+ const exported = exportedNode.type === "Identifier" ? prop(exportedNode, "name") : prop(exportedNode, "value");
126
+ parts.push(
127
+ `exports[${JSON.stringify(exported)}] = require(${JSON.stringify(source)})[${JSON.stringify(local)}];`
128
+ );
129
+ }
130
+ ms.overwrite(node.start, node.end, parts.join("\n"));
131
+ } else {
132
+ const parts = [];
133
+ for (const spec of prop(node, "specifiers")) {
134
+ const localNode = prop(spec, "local");
135
+ const exportedNode = prop(spec, "exported");
136
+ const local = localNode.type === "Identifier" ? prop(localNode, "name") : prop(localNode, "value");
137
+ const exported = exportedNode.type === "Identifier" ? prop(exportedNode, "name") : prop(exportedNode, "value");
138
+ parts.push(`exports[${JSON.stringify(exported)}] = ${local};`);
139
+ }
140
+ ms.overwrite(node.start, node.end, parts.join("\n"));
141
+ }
142
+ break;
143
+ }
144
+ case "ExportDefaultDeclaration": {
145
+ const decl = prop(node, "declaration");
146
+ if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") {
147
+ const id = prop(decl, "id");
148
+ if (id) {
149
+ ms.overwrite(node.start, decl.start, "");
150
+ ms.appendLeft(node.end, `
151
+ exports.default = ${prop(id, "name")};`);
152
+ } else {
153
+ ms.overwrite(node.start, decl.start, "exports.default = ");
154
+ }
155
+ } else {
156
+ ms.overwrite(node.start, decl.start, "exports.default = ");
157
+ if (code[node.end - 1] !== ";") {
158
+ ms.appendLeft(node.end, ";");
159
+ }
160
+ }
161
+ break;
162
+ }
163
+ case "ExportAllDeclaration": {
164
+ const source = prop(prop(node, "source"), "value");
165
+ const exportedNode = prop(node, "exported");
166
+ if (exportedNode) {
167
+ const name = exportedNode.type === "Identifier" ? prop(exportedNode, "name") : prop(exportedNode, "value");
168
+ ms.overwrite(node.start, node.end, `exports[${JSON.stringify(name)}] = require(${JSON.stringify(source)});`);
169
+ } else {
170
+ ms.overwrite(node.start, node.end, `Object.assign(exports, require(${JSON.stringify(source)}));`);
171
+ }
172
+ break;
173
+ }
174
+ }
175
+ }
176
+ ms.prepend('Object.defineProperty(exports, "__esModule", { value: true });\n');
177
+ return ms.toString();
178
+ }
15
179
  const debug$1 = createDebug("griffel:eval-cache");
16
180
  const fileHashes = /* @__PURE__ */ new Map();
17
181
  const evalCache = /* @__PURE__ */ new Map();
@@ -126,41 +290,6 @@ const mockProcess = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
126
290
  uvCounters
127
291
  }, Symbol.toStringTag, { value: "Module" }));
128
292
  const debug = createDebug("griffel:module");
129
- const builtins = {
130
- assert: true,
131
- buffer: true,
132
- child_process: false,
133
- cluster: false,
134
- console: true,
135
- constants: true,
136
- crypto: true,
137
- dgram: false,
138
- dns: false,
139
- domain: true,
140
- events: true,
141
- fs: false,
142
- http: true,
143
- https: true,
144
- module: false,
145
- net: false,
146
- os: true,
147
- path: true,
148
- punycode: true,
149
- process: true,
150
- querystring: true,
151
- readline: false,
152
- repl: false,
153
- stream: true,
154
- string_decoder: true,
155
- sys: true,
156
- timers: true,
157
- tls: false,
158
- tty: true,
159
- url: true,
160
- util: true,
161
- vm: true,
162
- zlib: true
163
- };
164
293
  let cache = {};
165
294
  const NOOP = () => {
166
295
  };
@@ -168,35 +297,23 @@ const createCustomDebug = (depth) => (namespaces, arg1, ...args) => {
168
297
  const modulePrefix = depth === 0 ? "module" : `sub-module-${depth}`;
169
298
  debug(`${modulePrefix}:${namespaces}`, arg1, ...args);
170
299
  };
171
- const BABEL_ESM = "/@babel/runtime/helpers/esm/";
172
- const BABEL_CJS = "/@babel/runtime/helpers/";
173
- const SWC_HELPERS_RE = /(@swc\/helpers\/)src(\/.+)\.mjs/;
174
- const cookModuleId = (rawId) => {
175
- const babelESMIndex = rawId.indexOf(BABEL_ESM);
176
- if (babelESMIndex !== -1) {
177
- return rawId.slice(0, babelESMIndex) + BABEL_CJS + rawId.slice(babelESMIndex + BABEL_ESM.length);
178
- }
179
- const swcHelpersIndex = rawId.indexOf("@swc/helpers/src/");
180
- if (swcHelpersIndex === -1) {
181
- return rawId.replace(SWC_HELPERS_RE, "$1lib$2.js");
182
- }
183
- return rawId;
184
- };
185
300
  class Module {
186
301
  id;
187
302
  filename;
188
- options;
303
+ rules;
189
304
  imports = null;
190
305
  dependencies = null;
191
306
  transform = null;
307
+ static extensions = /* @__PURE__ */ new Set([".json", ".js", ".jsx", ".ts", ".tsx", ".cjs", ".mjs", ".mts", ".cts"]);
192
308
  exports = {};
193
- extensions;
309
+ resolveFilename;
194
310
  debug;
195
311
  debuggerDepth;
196
- constructor(filename, options, debuggerDepth = 0) {
312
+ constructor(filename, rules, resolveFilename, debuggerDepth = 0) {
197
313
  this.id = filename;
198
314
  this.filename = filename;
199
- this.options = options;
315
+ this.rules = rules;
316
+ this.resolveFilename = resolveFilename;
200
317
  this.debuggerDepth = debuggerDepth;
201
318
  this.debug = createCustomDebug(debuggerDepth);
202
319
  Object.defineProperties(this, {
@@ -218,40 +335,16 @@ class Module {
218
335
  }
219
336
  });
220
337
  this.exports = {};
221
- this.extensions = [".json", ".js", ".jsx", ".ts", ".tsx", ".cjs"];
222
338
  this.debug("prepare", filename);
223
339
  }
224
- resolve = (rawId) => {
225
- const id = cookModuleId(rawId);
226
- const extensions = NativeModule._extensions;
227
- const added = [];
228
- try {
229
- this.extensions.forEach((ext) => {
230
- if (ext in extensions) {
231
- return;
232
- }
233
- extensions[ext] = NOOP;
234
- added.push(ext);
235
- });
236
- return Module._resolveFilename(id, this);
237
- } finally {
238
- added.forEach((ext) => delete extensions[ext]);
239
- }
240
- };
241
340
  require = Object.assign(
242
- (rawId) => {
243
- const id = cookModuleId(rawId);
341
+ (id) => {
244
342
  this.debug("require", id);
245
- if (id in builtins) {
246
- if (builtins[id]) {
247
- return require(id);
248
- }
249
- return null;
250
- }
251
- const filename = this.resolve(id);
252
- if (filename === id && !path.isAbsolute(id)) {
343
+ const resolved = this.resolveFilename(id, this);
344
+ if (resolved.builtin) {
253
345
  throw new Error(`Unable to import "${id}". Importing Node builtins is not supported in the sandbox.`);
254
346
  }
347
+ const filename = resolved.path;
255
348
  this.dependencies?.push(id);
256
349
  let cacheKey = filename;
257
350
  let only = [];
@@ -265,12 +358,13 @@ class Module {
265
358
  let m = cache[cacheKey];
266
359
  if (!m) {
267
360
  this.debug("cached:not-exist", id);
268
- m = new Module(filename, this.options, this.debuggerDepth + 1);
361
+ m = new Module(filename, this.rules, this.resolveFilename, this.debuggerDepth + 1);
269
362
  m.transform = this.transform;
270
363
  cache[cacheKey] = m;
271
- if (this.extensions.includes(path.extname(filename))) {
364
+ const ext = path.extname(filename).toLowerCase();
365
+ if (Module.extensions.has(ext)) {
272
366
  const code = fs.readFileSync(filename, "utf-8");
273
- if (/\.json$/.test(filename)) {
367
+ if (ext === ".json") {
274
368
  m.exports = JSON.parse(code);
275
369
  } else {
276
370
  m.evaluate(code, only.includes("*") ? ["*"] : only);
@@ -286,16 +380,16 @@ class Module {
286
380
  {
287
381
  ensure: NOOP,
288
382
  cache,
289
- resolve: this.resolve
383
+ resolve: (id) => this.resolveFilename(id, this).path
290
384
  }
291
385
  );
292
386
  evaluate(text, only = null) {
293
387
  const { filename } = this;
294
388
  let action = "ignore";
295
- for (let i = this.options.rules.length - 1; i >= 0; i--) {
296
- const { test } = this.options.rules[i];
297
- if (!test || (typeof test === "function" ? test(filename) : test instanceof RegExp && test.test(filename))) {
298
- action = this.options.rules[i].action;
389
+ for (let i = this.rules.length - 1; i >= 0; i--) {
390
+ const { test } = this.rules[i];
391
+ if (!test || (typeof test === "function" ? test(filename) : test.test(filename))) {
392
+ action = this.rules[i].action;
299
393
  break;
300
394
  }
301
395
  }
@@ -309,13 +403,13 @@ class Module {
309
403
  this.debug("ignore", `${filename}`);
310
404
  code = text;
311
405
  } else {
312
- const evaluator = typeof action === "function" ? action : require(require.resolve(action, {
313
- paths: [dirname(this.filename)]
314
- })).default;
315
- let imports;
316
- this.debug("prepare-evaluation", this.filename, "using", evaluator.name);
317
- [code, imports] = evaluator(this.filename, this.options, text, only);
318
- this.imports = imports;
406
+ this.debug("prepare-evaluation", this.filename, "using", action.name);
407
+ const result = action(this.filename, text, only);
408
+ code = result.code;
409
+ this.imports = result.imports;
410
+ if (result.moduleKind === "esm") {
411
+ code = convertESMtoCJS(code, this.filename);
412
+ }
319
413
  this.debug("evaluate", `${this.filename} (only ${(only || []).join(", ")}):
320
414
  ${code}`);
321
415
  }
@@ -331,6 +425,7 @@ ${code}`);
331
425
  setImmediate: NOOP,
332
426
  setInterval: NOOP,
333
427
  setTimeout: NOOP,
428
+ fetch: NOOP,
334
429
  global,
335
430
  process: mockProcess,
336
431
  module: this,
@@ -348,13 +443,6 @@ ${code}`);
348
443
  static invalidateEvalCache = () => {
349
444
  clear();
350
445
  };
351
- // Alias to resolve the module using node's resolve algorithm
352
- // This static property can be overridden by the webpack loader
353
- // This allows us to use webpack's module resolution algorithm
354
- static _resolveFilename = (id, options) => NativeModule._resolveFilename(
355
- id,
356
- options
357
- );
358
446
  static _nodeModulePaths = (filename) => NativeModule._nodeModulePaths(filename);
359
447
  }
360
448
  const DEOPT = /* @__PURE__ */ Symbol("deopt");
@@ -385,17 +473,17 @@ function astEvaluator(node, programAst, plugins = []) {
385
473
  }
386
474
  function evaluateObjectExpression(node2) {
387
475
  const obj = {};
388
- for (const prop of node2.properties) {
389
- if (prop.type !== "Property" || prop.kind !== "init") {
476
+ for (const prop2 of node2.properties) {
477
+ if (prop2.type !== "Property" || prop2.kind !== "init") {
390
478
  return DEOPT;
391
479
  }
392
480
  let key;
393
- if (prop.computed) {
481
+ if (prop2.computed) {
394
482
  return DEOPT;
395
- } else if (prop.key.type === "Identifier") {
396
- key = prop.key.name;
397
- } else if (prop.key.type === "Literal") {
398
- const keyLiteral = prop.key;
483
+ } else if (prop2.key.type === "Identifier") {
484
+ key = prop2.key.name;
485
+ } else if (prop2.key.type === "Literal") {
486
+ const keyLiteral = prop2.key;
399
487
  if (typeof keyLiteral.value === "string" || typeof keyLiteral.value === "number") {
400
488
  key = String(keyLiteral.value);
401
489
  } else {
@@ -404,7 +492,7 @@ function astEvaluator(node, programAst, plugins = []) {
404
492
  } else {
405
493
  return DEOPT;
406
494
  }
407
- const value = evaluateNode(prop.value);
495
+ const value = evaluateNode(prop2.value);
408
496
  if (value === DEOPT) {
409
497
  return DEOPT;
410
498
  }
@@ -427,34 +515,20 @@ function astEvaluator(node, programAst, plugins = []) {
427
515
  function isError(e) {
428
516
  return Object.prototype.toString.call(e) === "[object Error]";
429
517
  }
430
- function vmEvaluator(sourceCode, filename, expressionCode, babelOptions, evaluationRules) {
518
+ function vmEvaluator(sourceCode, filename, expressionCode, evaluationRules, resolveFilename) {
431
519
  const codeForEvaluation = `
432
520
  ${sourceCode}
433
521
 
434
- const __mkPreval = (() => {
522
+ export const __mkPreval = (() => {
435
523
  try {
436
524
  return ([${expressionCode}]);
437
525
  } catch (e) {
438
526
  return e;
439
527
  }
440
528
  })();
441
-
442
- if (typeof module !== 'undefined' && module.exports) {
443
- module.exports = { __mkPreval };
444
- }
445
529
  `;
446
530
  try {
447
- const options = {
448
- displayName: false,
449
- evaluate: true,
450
- rules: evaluationRules,
451
- babelOptions: {
452
- ...babelOptions,
453
- configFile: false,
454
- babelrc: false
455
- }
456
- };
457
- const mod = new Module(filename, options);
531
+ const mod = new Module(filename, evaluationRules, resolveFilename);
458
532
  mod.evaluate(codeForEvaluation, ["__mkPreval"]);
459
533
  const result = mod.exports.__mkPreval;
460
534
  if (isError(result)) {
@@ -465,10 +539,10 @@ if (typeof module !== 'undefined' && module.exports) {
465
539
  return { confident: false, error: err };
466
540
  }
467
541
  }
468
- function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluationRules, programAst, astEvaluationPlugins = []) {
542
+ function batchEvaluator(sourceCode, filename, styleCalls, evaluationRules, resolveFilename, programAst, astEvaluationPlugins = []) {
469
543
  const evaluationResults = new Array(styleCalls.length);
470
- const argumentsCode = new Array(styleCalls.length).fill(null);
471
- let vmEvaluationNeeded = false;
544
+ const vmIndices = [];
545
+ let expressionCode = "";
472
546
  for (let i = 0; i < styleCalls.length; i++) {
473
547
  const styleCall = styleCalls[i];
474
548
  const staticResult = astEvaluator(styleCall.argumentNode, programAst, astEvaluationPlugins);
@@ -476,16 +550,19 @@ function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluati
476
550
  evaluationResults[i] = staticResult.value;
477
551
  continue;
478
552
  }
479
- vmEvaluationNeeded = true;
480
- argumentsCode[i] = styleCall.argumentCode;
553
+ if (expressionCode.length > 0) {
554
+ expressionCode += ",";
555
+ }
556
+ expressionCode += styleCall.argumentCode;
557
+ vmIndices.push(i);
481
558
  }
482
- if (!vmEvaluationNeeded) {
559
+ if (vmIndices.length === 0) {
483
560
  return {
484
561
  usedVMForEvaluation: false,
485
562
  evaluationResults
486
563
  };
487
564
  }
488
- const vmResult = vmEvaluator(sourceCode, filename, argumentsCode.join(","), babelOptions, evaluationRules);
565
+ const vmResult = vmEvaluator(sourceCode, filename, expressionCode, evaluationRules, resolveFilename);
489
566
  if (!vmResult.confident) {
490
567
  if (vmResult.error) {
491
568
  throw vmResult.error;
@@ -494,45 +571,14 @@ function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluati
494
571
  }
495
572
  }
496
573
  const vmValues = vmResult.value;
497
- for (let i = 0; i < vmValues.length; i++) {
498
- if (vmValues[i] === null) {
499
- continue;
500
- }
501
- evaluationResults[i] = vmValues[i];
574
+ for (let i = 0; i < vmIndices.length; i++) {
575
+ evaluationResults[vmIndices[i]] = vmValues[i];
502
576
  }
503
577
  return {
504
578
  usedVMForEvaluation: true,
505
579
  evaluationResults
506
580
  };
507
581
  }
508
- const CJS_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".json"]);
509
- const ESM_EXTENSIONS = /* @__PURE__ */ new Set([".mjs", ".mts"]);
510
- const useRawTransfer = rawTransferSupported();
511
- const NODE_MODULES_RE = /[/\\]node_modules[/\\]/;
512
- function createHybridEvaluator(shakerEvaluator2) {
513
- return (filename, options, text, only) => {
514
- if (!NODE_MODULES_RE.test(filename)) {
515
- return shakerEvaluator2(filename, options, text, only);
516
- }
517
- const ext = extname(filename);
518
- if (CJS_EXTENSIONS.has(ext)) {
519
- return [text, null];
520
- }
521
- if (ESM_EXTENSIONS.has(ext)) {
522
- return shakerEvaluator2(filename, options, text, only);
523
- }
524
- const parseResult = parseSync(filename, text, {
525
- sourceType: "unambiguous",
526
- ...useRawTransfer && { experimentalLazy: true }
527
- });
528
- const isESM = parseResult.module.hasModuleSyntax;
529
- parseResult.dispose?.();
530
- if (!isESM) {
531
- return [text, null];
532
- }
533
- return shakerEvaluator2(filename, options, text, only);
534
- };
535
- }
536
582
  function evaluateTemplateLiteralWithTokens(node) {
537
583
  let result = "";
538
584
  for (let i = 0; i < node.quasis.length; i++) {
@@ -584,7 +630,18 @@ function dedupeCSSRules(cssRulesByBucket) {
584
630
  })
585
631
  );
586
632
  }
587
- const shakerEvaluator = _shaker.default || _shaker;
633
+ const EXPORT_STAR_RE = /export\s+\*\s+from\s/;
634
+ function wrapWithPerfIssues(evaluator, perfIssues) {
635
+ return (filename, text, only) => {
636
+ const result = evaluator(filename, text, only);
637
+ if (result.moduleKind === "cjs") {
638
+ perfIssues.push({ type: "cjs-module", dependencyFilename: filename });
639
+ } else if (EXPORT_STAR_RE.test(result.code)) {
640
+ perfIssues.push({ type: "barrel-export-star", dependencyFilename: filename });
641
+ }
642
+ return result;
643
+ };
644
+ }
588
645
  const RUNTIME_IDENTIFIERS = /* @__PURE__ */ new Map([
589
646
  ["makeStyles", "__css"],
590
647
  ["makeResetStyles", "__resetCSS"],
@@ -650,13 +707,14 @@ function concatCSSRulesByBucket(bucketA = {}, bucketB) {
650
707
  return bucketA;
651
708
  }
652
709
  function transformSync(sourceCode, options) {
710
+ const perfIssues = options.collectPerfIssues ? [] : void 0;
653
711
  const {
654
- babelOptions = {},
655
712
  filename,
713
+ resolveModule,
656
714
  classNameHashSalt = "",
657
715
  generateMetadata = false,
658
716
  modules = ["@griffel/core", "@griffel/react", "@fluentui/react-components"],
659
- evaluationRules = [{ action: createHybridEvaluator(shakerEvaluator) }],
717
+ evaluationRules = [{ action: perfIssues ? wrapWithPerfIssues(shakerEvaluator, perfIssues) : shakerEvaluator }],
660
718
  astEvaluationPlugins = [fluentTokensPlugin]
661
719
  } = options;
662
720
  if (!filename) {
@@ -756,8 +814,8 @@ function transformSync(sourceCode, options) {
756
814
  sourceCode,
757
815
  filename,
758
816
  styleCalls,
759
- babelOptions,
760
817
  evaluationRules,
818
+ resolveModule,
761
819
  programAst,
762
820
  astEvaluationPlugins
763
821
  );
@@ -820,7 +878,8 @@ function transformSync(sourceCode, options) {
820
878
  code: magicString.toString(),
821
879
  cssRulesByBucket,
822
880
  usedProcessing: true,
823
- usedVMForEvaluation
881
+ usedVMForEvaluation,
882
+ perfIssues
824
883
  };
825
884
  }
826
885
  export {
@@ -1,7 +1,10 @@
1
- import { StrictOptions, AstEvaluatorPlugin } from './evaluation/types.mjs';
1
+ import { TransformResolver } from './evaluation/module.mjs';
2
+ import { EvalRule, TransformPerfIssue, AstEvaluatorPlugin } from './evaluation/types.mjs';
2
3
  import { CSSRulesByBucket } from '@griffel/core';
3
4
  export type TransformOptions = {
4
5
  filename: string;
6
+ /** Custom module resolver used to resolve imports inside evaluated modules. */
7
+ resolveModule: TransformResolver;
5
8
  classNameHashSalt?: string;
6
9
  /**
7
10
  * Returns the evaluated CSS rules in the file result metadata
@@ -10,21 +13,22 @@ export type TransformOptions = {
10
13
  generateMetadata?: boolean;
11
14
  /** Defines set of modules and imports handled by a transformPlugin. */
12
15
  modules?: string[];
13
- /**
14
- * If you need to specify custom Babel configuration, you can pass them here. These options will be used by the
15
- * transformPlugin when parsing and evaluating modules.
16
- */
17
- babelOptions?: Pick<StrictOptions['babelOptions'], 'plugins' | 'presets'>;
18
16
  /** The set of rules that defines how the matched files will be transformed during the evaluation. */
19
- evaluationRules?: StrictOptions['rules'];
17
+ evaluationRules?: EvalRule[];
20
18
  /** Plugins for extending AST evaluation with custom node handling. */
21
19
  astEvaluationPlugins?: AstEvaluatorPlugin[];
20
+ /**
21
+ * Collects performance issues (CJS modules, barrel re-exports) during evaluation.
22
+ * @default false
23
+ */
24
+ collectPerfIssues?: boolean;
22
25
  };
23
26
  export type TransformResult = {
24
27
  code: string;
25
28
  cssRulesByBucket?: CSSRulesByBucket;
26
29
  usedProcessing: boolean;
27
30
  usedVMForEvaluation: boolean;
31
+ perfIssues?: TransformPerfIssue[];
28
32
  };
29
33
  /**
30
34
  * Transforms passed source code with oxc-parser and oxc-walker instead of Babel.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Converts ESM import/export syntax to CJS require/exports equivalents.
3
+ * This is needed because the VM evaluator wraps code in `(function(exports) { ... })(exports)`
4
+ * which cannot contain ESM syntax.
5
+ */
6
+ export declare function convertESMtoCJS(code: string, filename: string): string;
@@ -1,2 +0,0 @@
1
- import { Evaluator } from './types.mjs';
2
- export declare function createHybridEvaluator(shakerEvaluator: Evaluator): Evaluator;