@griffel/transform 1.2.1 → 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,25 @@
1
1
  # Change Log - @griffel/transform
2
2
 
3
- This log was last generated on Fri, 06 Mar 2026 15:54:55 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
+
7
20
  ## 1.2.1
8
21
 
9
- Fri, 06 Mar 2026 15:54:55 GMT
22
+ Fri, 06 Mar 2026 15:56:28 GMT
10
23
 
11
24
  ### Patches
12
25
 
@@ -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: (id: 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.1",
3
+ "version": "2.0.0",
4
4
  "description": "A package that performs build time transforms for Griffel",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@griffel/core": "^1.20.1",
20
- "@linaria/shaker": "^3.0.0-beta.22",
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
  };
@@ -171,18 +300,20 @@ const createCustomDebug = (depth) => (namespaces, arg1, ...args) => {
171
300
  class Module {
172
301
  id;
173
302
  filename;
174
- options;
303
+ rules;
175
304
  imports = null;
176
305
  dependencies = null;
177
306
  transform = null;
307
+ static extensions = /* @__PURE__ */ new Set([".json", ".js", ".jsx", ".ts", ".tsx", ".cjs", ".mjs", ".mts", ".cts"]);
178
308
  exports = {};
179
- extensions;
309
+ resolveFilename;
180
310
  debug;
181
311
  debuggerDepth;
182
- constructor(filename, options, debuggerDepth = 0) {
312
+ constructor(filename, rules, resolveFilename, debuggerDepth = 0) {
183
313
  this.id = filename;
184
314
  this.filename = filename;
185
- this.options = options;
315
+ this.rules = rules;
316
+ this.resolveFilename = resolveFilename;
186
317
  this.debuggerDepth = debuggerDepth;
187
318
  this.debug = createCustomDebug(debuggerDepth);
188
319
  Object.defineProperties(this, {
@@ -204,38 +335,16 @@ class Module {
204
335
  }
205
336
  });
206
337
  this.exports = {};
207
- this.extensions = [".json", ".js", ".jsx", ".ts", ".tsx", ".cjs"];
208
338
  this.debug("prepare", filename);
209
339
  }
210
- resolve = (id) => {
211
- const extensions = NativeModule._extensions;
212
- const added = [];
213
- try {
214
- this.extensions.forEach((ext) => {
215
- if (ext in extensions) {
216
- return;
217
- }
218
- extensions[ext] = NOOP;
219
- added.push(ext);
220
- });
221
- return Module._resolveFilename(id, this);
222
- } finally {
223
- added.forEach((ext) => delete extensions[ext]);
224
- }
225
- };
226
340
  require = Object.assign(
227
341
  (id) => {
228
342
  this.debug("require", id);
229
- if (id in builtins) {
230
- if (builtins[id]) {
231
- return require(id);
232
- }
233
- return null;
234
- }
235
- const filename = this.resolve(id);
236
- if (filename === id && !path.isAbsolute(id)) {
343
+ const resolved = this.resolveFilename(id, this);
344
+ if (resolved.builtin) {
237
345
  throw new Error(`Unable to import "${id}". Importing Node builtins is not supported in the sandbox.`);
238
346
  }
347
+ const filename = resolved.path;
239
348
  this.dependencies?.push(id);
240
349
  let cacheKey = filename;
241
350
  let only = [];
@@ -249,12 +358,13 @@ class Module {
249
358
  let m = cache[cacheKey];
250
359
  if (!m) {
251
360
  this.debug("cached:not-exist", id);
252
- m = new Module(filename, this.options, this.debuggerDepth + 1);
361
+ m = new Module(filename, this.rules, this.resolveFilename, this.debuggerDepth + 1);
253
362
  m.transform = this.transform;
254
363
  cache[cacheKey] = m;
255
- if (this.extensions.includes(path.extname(filename))) {
364
+ const ext = path.extname(filename).toLowerCase();
365
+ if (Module.extensions.has(ext)) {
256
366
  const code = fs.readFileSync(filename, "utf-8");
257
- if (/\.json$/.test(filename)) {
367
+ if (ext === ".json") {
258
368
  m.exports = JSON.parse(code);
259
369
  } else {
260
370
  m.evaluate(code, only.includes("*") ? ["*"] : only);
@@ -270,16 +380,16 @@ class Module {
270
380
  {
271
381
  ensure: NOOP,
272
382
  cache,
273
- resolve: this.resolve
383
+ resolve: (id) => this.resolveFilename(id, this).path
274
384
  }
275
385
  );
276
386
  evaluate(text, only = null) {
277
387
  const { filename } = this;
278
388
  let action = "ignore";
279
- for (let i = this.options.rules.length - 1; i >= 0; i--) {
280
- const { test } = this.options.rules[i];
281
- if (!test || (typeof test === "function" ? test(filename) : test instanceof RegExp && test.test(filename))) {
282
- 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;
283
393
  break;
284
394
  }
285
395
  }
@@ -293,13 +403,13 @@ class Module {
293
403
  this.debug("ignore", `${filename}`);
294
404
  code = text;
295
405
  } else {
296
- const evaluator = typeof action === "function" ? action : require(require.resolve(action, {
297
- paths: [dirname(this.filename)]
298
- })).default;
299
- let imports;
300
- this.debug("prepare-evaluation", this.filename, "using", evaluator.name);
301
- [code, imports] = evaluator(this.filename, this.options, text, only);
302
- 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
+ }
303
413
  this.debug("evaluate", `${this.filename} (only ${(only || []).join(", ")}):
304
414
  ${code}`);
305
415
  }
@@ -315,6 +425,7 @@ ${code}`);
315
425
  setImmediate: NOOP,
316
426
  setInterval: NOOP,
317
427
  setTimeout: NOOP,
428
+ fetch: NOOP,
318
429
  global,
319
430
  process: mockProcess,
320
431
  module: this,
@@ -332,13 +443,6 @@ ${code}`);
332
443
  static invalidateEvalCache = () => {
333
444
  clear();
334
445
  };
335
- // Alias to resolve the module using node's resolve algorithm
336
- // This static property can be overridden by the webpack loader
337
- // This allows us to use webpack's module resolution algorithm
338
- static _resolveFilename = (id, options) => NativeModule._resolveFilename(
339
- id,
340
- options
341
- );
342
446
  static _nodeModulePaths = (filename) => NativeModule._nodeModulePaths(filename);
343
447
  }
344
448
  const DEOPT = /* @__PURE__ */ Symbol("deopt");
@@ -369,17 +473,17 @@ function astEvaluator(node, programAst, plugins = []) {
369
473
  }
370
474
  function evaluateObjectExpression(node2) {
371
475
  const obj = {};
372
- for (const prop of node2.properties) {
373
- if (prop.type !== "Property" || prop.kind !== "init") {
476
+ for (const prop2 of node2.properties) {
477
+ if (prop2.type !== "Property" || prop2.kind !== "init") {
374
478
  return DEOPT;
375
479
  }
376
480
  let key;
377
- if (prop.computed) {
481
+ if (prop2.computed) {
378
482
  return DEOPT;
379
- } else if (prop.key.type === "Identifier") {
380
- key = prop.key.name;
381
- } else if (prop.key.type === "Literal") {
382
- 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;
383
487
  if (typeof keyLiteral.value === "string" || typeof keyLiteral.value === "number") {
384
488
  key = String(keyLiteral.value);
385
489
  } else {
@@ -388,7 +492,7 @@ function astEvaluator(node, programAst, plugins = []) {
388
492
  } else {
389
493
  return DEOPT;
390
494
  }
391
- const value = evaluateNode(prop.value);
495
+ const value = evaluateNode(prop2.value);
392
496
  if (value === DEOPT) {
393
497
  return DEOPT;
394
498
  }
@@ -411,34 +515,20 @@ function astEvaluator(node, programAst, plugins = []) {
411
515
  function isError(e) {
412
516
  return Object.prototype.toString.call(e) === "[object Error]";
413
517
  }
414
- function vmEvaluator(sourceCode, filename, expressionCode, babelOptions, evaluationRules) {
518
+ function vmEvaluator(sourceCode, filename, expressionCode, evaluationRules, resolveFilename) {
415
519
  const codeForEvaluation = `
416
520
  ${sourceCode}
417
521
 
418
- const __mkPreval = (() => {
522
+ export const __mkPreval = (() => {
419
523
  try {
420
524
  return ([${expressionCode}]);
421
525
  } catch (e) {
422
526
  return e;
423
527
  }
424
528
  })();
425
-
426
- if (typeof module !== 'undefined' && module.exports) {
427
- module.exports = { __mkPreval };
428
- }
429
529
  `;
430
530
  try {
431
- const options = {
432
- displayName: false,
433
- evaluate: true,
434
- rules: evaluationRules,
435
- babelOptions: {
436
- ...babelOptions,
437
- configFile: false,
438
- babelrc: false
439
- }
440
- };
441
- const mod = new Module(filename, options);
531
+ const mod = new Module(filename, evaluationRules, resolveFilename);
442
532
  mod.evaluate(codeForEvaluation, ["__mkPreval"]);
443
533
  const result = mod.exports.__mkPreval;
444
534
  if (isError(result)) {
@@ -449,10 +539,10 @@ if (typeof module !== 'undefined' && module.exports) {
449
539
  return { confident: false, error: err };
450
540
  }
451
541
  }
452
- function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluationRules, programAst, astEvaluationPlugins = []) {
542
+ function batchEvaluator(sourceCode, filename, styleCalls, evaluationRules, resolveFilename, programAst, astEvaluationPlugins = []) {
453
543
  const evaluationResults = new Array(styleCalls.length);
454
- const argumentsCode = new Array(styleCalls.length).fill(null);
455
- let vmEvaluationNeeded = false;
544
+ const vmIndices = [];
545
+ let expressionCode = "";
456
546
  for (let i = 0; i < styleCalls.length; i++) {
457
547
  const styleCall = styleCalls[i];
458
548
  const staticResult = astEvaluator(styleCall.argumentNode, programAst, astEvaluationPlugins);
@@ -460,16 +550,19 @@ function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluati
460
550
  evaluationResults[i] = staticResult.value;
461
551
  continue;
462
552
  }
463
- vmEvaluationNeeded = true;
464
- argumentsCode[i] = styleCall.argumentCode;
553
+ if (expressionCode.length > 0) {
554
+ expressionCode += ",";
555
+ }
556
+ expressionCode += styleCall.argumentCode;
557
+ vmIndices.push(i);
465
558
  }
466
- if (!vmEvaluationNeeded) {
559
+ if (vmIndices.length === 0) {
467
560
  return {
468
561
  usedVMForEvaluation: false,
469
562
  evaluationResults
470
563
  };
471
564
  }
472
- const vmResult = vmEvaluator(sourceCode, filename, argumentsCode.join(","), babelOptions, evaluationRules);
565
+ const vmResult = vmEvaluator(sourceCode, filename, expressionCode, evaluationRules, resolveFilename);
473
566
  if (!vmResult.confident) {
474
567
  if (vmResult.error) {
475
568
  throw vmResult.error;
@@ -478,45 +571,14 @@ function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluati
478
571
  }
479
572
  }
480
573
  const vmValues = vmResult.value;
481
- for (let i = 0; i < vmValues.length; i++) {
482
- if (vmValues[i] === null) {
483
- continue;
484
- }
485
- evaluationResults[i] = vmValues[i];
574
+ for (let i = 0; i < vmIndices.length; i++) {
575
+ evaluationResults[vmIndices[i]] = vmValues[i];
486
576
  }
487
577
  return {
488
578
  usedVMForEvaluation: true,
489
579
  evaluationResults
490
580
  };
491
581
  }
492
- const CJS_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".json"]);
493
- const ESM_EXTENSIONS = /* @__PURE__ */ new Set([".mjs", ".mts"]);
494
- const useRawTransfer = rawTransferSupported();
495
- const NODE_MODULES_RE = /[/\\]node_modules[/\\]/;
496
- function createHybridEvaluator(shakerEvaluator2) {
497
- return (filename, options, text, only) => {
498
- if (!NODE_MODULES_RE.test(filename)) {
499
- return shakerEvaluator2(filename, options, text, only);
500
- }
501
- const ext = extname(filename);
502
- if (CJS_EXTENSIONS.has(ext)) {
503
- return [text, null];
504
- }
505
- if (ESM_EXTENSIONS.has(ext)) {
506
- return shakerEvaluator2(filename, options, text, only);
507
- }
508
- const parseResult = parseSync(filename, text, {
509
- sourceType: "unambiguous",
510
- ...useRawTransfer && { experimentalLazy: true }
511
- });
512
- const isESM = parseResult.module.hasModuleSyntax;
513
- parseResult.dispose?.();
514
- if (!isESM) {
515
- return [text, null];
516
- }
517
- return shakerEvaluator2(filename, options, text, only);
518
- };
519
- }
520
582
  function evaluateTemplateLiteralWithTokens(node) {
521
583
  let result = "";
522
584
  for (let i = 0; i < node.quasis.length; i++) {
@@ -568,7 +630,18 @@ function dedupeCSSRules(cssRulesByBucket) {
568
630
  })
569
631
  );
570
632
  }
571
- 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
+ }
572
645
  const RUNTIME_IDENTIFIERS = /* @__PURE__ */ new Map([
573
646
  ["makeStyles", "__css"],
574
647
  ["makeResetStyles", "__resetCSS"],
@@ -634,13 +707,14 @@ function concatCSSRulesByBucket(bucketA = {}, bucketB) {
634
707
  return bucketA;
635
708
  }
636
709
  function transformSync(sourceCode, options) {
710
+ const perfIssues = options.collectPerfIssues ? [] : void 0;
637
711
  const {
638
- babelOptions = {},
639
712
  filename,
713
+ resolveModule,
640
714
  classNameHashSalt = "",
641
715
  generateMetadata = false,
642
716
  modules = ["@griffel/core", "@griffel/react", "@fluentui/react-components"],
643
- evaluationRules = [{ action: createHybridEvaluator(shakerEvaluator) }],
717
+ evaluationRules = [{ action: perfIssues ? wrapWithPerfIssues(shakerEvaluator, perfIssues) : shakerEvaluator }],
644
718
  astEvaluationPlugins = [fluentTokensPlugin]
645
719
  } = options;
646
720
  if (!filename) {
@@ -740,8 +814,8 @@ function transformSync(sourceCode, options) {
740
814
  sourceCode,
741
815
  filename,
742
816
  styleCalls,
743
- babelOptions,
744
817
  evaluationRules,
818
+ resolveModule,
745
819
  programAst,
746
820
  astEvaluationPlugins
747
821
  );
@@ -804,7 +878,8 @@ function transformSync(sourceCode, options) {
804
878
  code: magicString.toString(),
805
879
  cssRulesByBucket,
806
880
  usedProcessing: true,
807
- usedVMForEvaluation
881
+ usedVMForEvaluation,
882
+ perfIssues
808
883
  };
809
884
  }
810
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;