Repository: microsoft/griffel
Pull request #291 (2022-12-07 15:40:01)

chore: remove path magic in extraction process
With changes in this PR we don't use this file anymore. The recipe is described in [Webpack's documentation](https://webpack.js.org/api/loaders/#inline-matchresource). It was impossible to do it before #277, but now we don't rely on `cacheGroups` anymore.

## Before

CSS was was emitted to a fake file `griffel.css` in the virtual loader, this file has a path that might look like `node_modules/@griffel/webpack-extraction-plugin/virtual-loader/griffel.css`. Image files are relative to the userland code
file, so we had to construct a relative path from the fake CSS file to the image file in userland code.

## After

The fake `griffel.css` file is is under the same path as the original code file, so there is no need to do any changes to the image path since it will already be relative to the original code file.


Patch:
diff --git a/change/@griffel-webpack-extraction-plugin-bba7ffbb-7ebd-42a2-a707-04ab557a8d8f.json b/change/@griffel-webpack-extraction-plugin-bba7ffbb-7ebd-42a2-a707-04ab557a8d8f.json
new file mode 100644
index 0000000..2c0c4d6
--- /dev/null
+++ b/change/@griffel-webpack-extraction-plugin-bba7ffbb-7ebd-42a2-a707-04ab557a8d8f.json
@@ -0,0 +1,7 @@
+{
+  "type": "patch",
+  "comment": "chore: remove path magic in extraction process",
+  "packageName": "@griffel/webpack-extraction-plugin",
+  "email": "olfedias@microsoft.com",
+  "dependentChangeType": "patch"
+}
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/assets-multiple/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/assets-multiple/output.ts
index 51d1b76..b53ab79 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/assets-multiple/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/assets-multiple/output.ts
@@ -5,4 +5,4 @@ export const useStyles = __css({
   },
 });
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fp00rh9%7Bbackground-image%3Aurl(..%2F__fixtures__%2Fwebpack%2Fassets-multiple%2Fblank.jpg)%2Curl(..%2F__fixtures__%2Fwebpack%2Fassets-multiple%2Fempty.jpg)%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fp00rh9%7Bbackground-image%3Aurl(.%2Fblank.jpg)%2Curl(.%2Fempty.jpg)%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/assets/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/assets/output.ts
index df00930..ac34f90 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/assets/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/assets/output.ts
@@ -5,4 +5,4 @@ export const useStyles = __css({
   },
 });
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fnwsaxv%7Bbackground-image%3Aurl(..%2F__fixtures__%2Fwebpack%2Fassets%2Fblank.jpg)%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fnwsaxv%7Bbackground-image%3Aurl(.%2Fblank.jpg)%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/basic-rules/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/basic-rules/output.ts
index 56ad088..dd51f76 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/basic-rules/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/basic-rules/output.ts
@@ -10,4 +10,4 @@ export const styles = __css({
   },
 });
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fe3e8s9%7Bcolor%3Ared%3B%7D.fycuoez%7Bpadding-left%3A4px%3B%7D.f8wuabp%7Bpadding-right%3A4px%3B%7D.fcnqdeg%7Bbackground-color%3Agreen%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fe3e8s9%7Bcolor%3Ared%3B%7D.fycuoez%7Bpadding-left%3A4px%3B%7D.f8wuabp%7Bpadding-right%3A4px%3B%7D.fcnqdeg%7Bbackground-color%3Agreen%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/mixed/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/mixed/output.ts
index b670831..c43ec4d 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/mixed/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/mixed/output.ts
@@ -6,4 +6,4 @@ export const useClasses = __css({
 });
 export const useClassName = __resetCSS('rjefjbm', 'r7z97ji');
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fe3e8s9%7Bcolor%3Ared%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A%2F**%20%40griffel%3Acss-start%20%5Br%5D%20**%2F%0A.rjefjbm%7Bcolor%3Ared%3Bpadding-left%3A4px%3B%7D.r7z97ji%7Bcolor%3Ared%3Bpadding-right%3A4px%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fe3e8s9%7Bcolor%3Ared%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A%2F**%20%40griffel%3Acss-start%20%5Br%5D%20**%2F%0A.rjefjbm%7Bcolor%3Ared%3Bpadding-left%3A4px%3B%7D.r7z97ji%7Bcolor%3Ared%3Bpadding-right%3A4px%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/multiple/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/multiple/output.ts
index 5450176..691b6b6 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/multiple/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/multiple/output.ts
@@ -10,4 +10,4 @@ export const stylesB = __css({
   },
 });
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fcnqdeg%7Bbackground-color%3Agreen%3B%7D.fe3e8s9%7Bcolor%3Ared%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Bd%5D%20**%2F%0A.fcnqdeg%7Bbackground-color%3Agreen%3B%7D.fe3e8s9%7Bcolor%3Ared%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/reset-assets/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/reset-assets/output.ts
index 7283d9e..b2c42e3 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/reset-assets/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/reset-assets/output.ts
@@ -1,4 +1,4 @@
 import { __resetStyles, __resetCSS } from '@griffel/react';
 export const useClassName = __resetCSS('ra9m047', null);
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Br%5D%20**%2F%0A.ra9m047%7Bbackground-image%3Aurl(..%2F__fixtures__%2Fwebpack%2Freset-assets%2Fblank.jpg)%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Br%5D%20**%2F%0A.ra9m047%7Bbackground-image%3Aurl(.%2Fblank.jpg)%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/__fixtures__/webpack/reset/output.ts b/packages/webpack-extraction-plugin/__fixtures__/webpack/reset/output.ts
index 9380ff8..585a40e 100644
--- a/packages/webpack-extraction-plugin/__fixtures__/webpack/reset/output.ts
+++ b/packages/webpack-extraction-plugin/__fixtures__/webpack/reset/output.ts
@@ -1,4 +1,4 @@
 import { __resetStyles, __resetCSS } from '@griffel/react';
 export const useClassName = __resetCSS('rjefjbm', 'r7z97ji');
 
-import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=%2F**%20%40griffel%3Acss-start%20%5Br%5D%20**%2F%0A.rjefjbm%7Bcolor%3Ared%3Bpadding-left%3A4px%3B%7D.r7z97ji%7Bcolor%3Ared%3Bpadding-right%3A4px%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A';
+require('./code.griffel.css!=!../../../virtual-loader/index.js?style=%2F**%20%40griffel%3Acss-start%20%5Br%5D%20**%2F%0A.rjefjbm%7Bcolor%3Ared%3Bpadding-left%3A4px%3B%7D.r7z97ji%7Bcolor%3Ared%3Bpadding-right%3A4px%3B%7D%0A%2F**%20%40griffel%3Acss-end%20**%2F%0A!./code.ts');
diff --git a/packages/webpack-extraction-plugin/project.json b/packages/webpack-extraction-plugin/project.json
index 13cd794..0afcbde 100644
--- a/packages/webpack-extraction-plugin/project.json
+++ b/packages/webpack-extraction-plugin/project.json
@@ -34,7 +34,7 @@
             "output": "."
           },
           {
-            "glob": "*.{js,css}",
+            "glob": "*.js",
             "input": "packages/webpack-extraction-plugin/virtual-loader",
             "output": "./virtual-loader"
           }
diff --git a/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.ts b/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.ts
index f25014e..dc17c87 100644
--- a/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.ts
+++ b/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.ts
@@ -1,12 +1,8 @@
 import { NodePath, PluginObj, PluginPass, types as t } from '@babel/core';
 import { declare } from '@babel/helper-plugin-utils';
 import type { CSSRulesByBucket } from '@griffel/core';
-import * as path from 'path';
 
-type StripRuntimeBabelPluginOptions = {
-  /** A directory that contains fake .css file used for CSS extraction */
-  resourceDirectory?: string;
-};
+type StripRuntimeBabelPluginOptions = Record<string, unknown>;
 
 type FunctionKinds = '__styles' | '__resetStyles';
 
@@ -18,18 +14,6 @@ export type StripRuntimeBabelPluginMetadata = {
   cssRulesByBucket?: CSSRulesByBucket;
 };
 
-export function transformUrl(filename: string, resourceDirectory: string, assetPath: string) {
-  // Get the absolute path to the asset from the path relative to the JS file
-  const absoluteAssetPath = path.resolve(path.dirname(filename), assetPath);
-
-  // Replace asset path with new path relative to the output CSS
-  const relativeAssetPath = path.relative(resourceDirectory, absoluteAssetPath);
-
-  // Normalize paths to be POSIX-like as bundlers don't handle Windows paths
-  // "path.posix" does not make sense there as there is no "windows-to-posix-path" function
-  return relativeAssetPath.split(path.sep).join(path.posix.sep);
-}
-
 function concatCSSRulesByBucket(bucketA: CSSRulesByBucket = {}, bucketB: CSSRulesByBucket) {
   Object.entries(bucketB).forEach(([cssBucketName, cssBucketEntries]) => {
     bucketA[cssBucketName as keyof CSSRulesByBucket] = cssBucketEntries.concat(
@@ -43,7 +27,7 @@ function concatCSSRulesByBucket(bucketA: CSSRulesByBucket = {}, bucketB: CSSRule
 export const babelPluginStripGriffelRuntime = declare<
   Partial<StripRuntimeBabelPluginOptions>,
   PluginObj<StripRuntimeBabelPluginState>
->((api, options) => {
+>(api => {
   api.assertVersion(7);
 
   return {
@@ -55,17 +39,6 @@ export const babelPluginStripGriffelRuntime = declare<
     visitor: {
       Program: {
         enter(path, state) {
-          if (typeof options.resourceDirectory === 'undefined') {
-            throw new Error(
-              [
-                '@griffel/webpack-extraction-plugin: This plugin requires "resourceDirectory" option to be specified. ',
-                "It's automatically done by our loaders. ",
-                "If you're facing this issue, please check your setup.\n\n",
-                'See: https://babeljs.io/docs/en/options#filename',
-              ].join(''),
-            );
-          }
-
           if (typeof state.filename === 'undefined') {
             throw new Error(
               [
@@ -191,17 +164,7 @@ export const babelPluginStripGriffelRuntime = declare<
                       );
                     }
 
-                    expressionPath.replaceWith(
-                      t.stringLiteral(
-                        // When imports are inlined, we need to adjust the relative paths inside url(..) expressions
-                        // to allow css-loader resolve an imported asset properly
-                        transformUrl(
-                          state.filename!,
-                          options.resourceDirectory!,
-                          importDeclarationPath.get('source').node.value,
-                        ),
-                      ),
-                    );
+                    expressionPath.replaceWith(t.stringLiteral(importDeclarationPath.get('source').node.value));
                     importDeclarationPath.remove();
                   });
                 },
diff --git a/packages/webpack-extraction-plugin/src/transformSync.ts b/packages/webpack-extraction-plugin/src/transformSync.ts
index 7daf4f7..4dcd316 100644
--- a/packages/webpack-extraction-plugin/src/transformSync.ts
+++ b/packages/webpack-extraction-plugin/src/transformSync.ts
@@ -5,7 +5,6 @@ import { babelPluginStripGriffelRuntime, StripRuntimeBabelPluginMetadata } from
 
 export type TransformOptions = {
   filename: string;
-  resourceDirectory: string;
 
   inputSourceMap: Babel.TransformOptions['inputSourceMap'];
   enableSourceMaps: boolean;
@@ -39,7 +38,7 @@ export function transformSync(sourceCode: string, options: TransformOptions): Tr
     // Ignore all user's configs and apply only our plugin
     babelrc: false,
     configFile: false,
-    plugins: [[babelPluginStripGriffelRuntime, { resourceDirectory: options.resourceDirectory }]],
+    plugins: [babelPluginStripGriffelRuntime],
 
     filename: options.filename,
 
diff --git a/packages/webpack-extraction-plugin/src/webpackLoader.ts b/packages/webpack-extraction-plugin/src/webpackLoader.ts
index de7f1c4..131432e 100644
--- a/packages/webpack-extraction-plugin/src/webpackLoader.ts
+++ b/packages/webpack-extraction-plugin/src/webpackLoader.ts
@@ -8,10 +8,7 @@ type WebpackLoaderOptions = never;
 
 type WebpackLoaderParams = Parameters<webpack.LoaderDefinitionFunction<WebpackLoaderOptions>>;
 
-const resourceDirectory = path.resolve(__dirname, '..', 'virtual-loader');
-
-const virtualLoaderPath = path.resolve(resourceDirectory, 'index.js');
-const resourcePath = path.resolve(resourceDirectory, 'griffel.css');
+const virtualLoaderPath = path.resolve(__dirname, '..', 'virtual-loader', 'index.js');
 
 function toURIComponent(rule: string): string {
   return encodeURIComponent(rule).replace(/!/g, '%21');
@@ -55,7 +52,6 @@ function webpackLoader(
   try {
     result = transformSync(sourceCode, {
       filename: path.relative(process.cwd(), this.resourcePath),
-      resourceDirectory,
 
       enableSourceMaps: this.sourceMap || false,
       inputSourceMap: parseSourceMap(inputSourceMap),
@@ -94,14 +90,19 @@ function webpackLoader(
         );
       }, '');
 
-      const request = `import ${JSON.stringify(
-        this.utils.contextify(
-          this.context || this.rootContext,
-          `griffel.css!=!${virtualLoaderPath}!${resourcePath}?style=${toURIComponent(css)}`,
-        ),
-      )};`;
+      const outputFileName = this.resourcePath.replace(/\.[^.]+$/, '.griffel.css');
+
+      const request = `${outputFileName}!=!${virtualLoaderPath}?style=${toURIComponent(css)}!${this.resourcePath}`;
+      const stringifiedRequest = JSON.stringify(this.utils.contextify(this.context || this.rootContext, request));
 
-      this.callback(null, `${result.code}\n\n${request};`, result.sourceMap);
+      this.callback(
+        null,
+        // Heads up!
+        // This is probably a bug, but "import" does not work properly there: files from node_modules are processed, but
+        // they will not be present in chunks 😳
+        `${result.code}\n\nrequire(${stringifiedRequest});`,
+        result.sourceMap,
+      );
       return;
     }
 
diff --git a/packages/webpack-extraction-plugin/virtual-loader/griffel.css b/packages/webpack-extraction-plugin/virtual-loader/griffel.css
deleted file mode 100644
index 24590f7..0000000
--- a/packages/webpack-extraction-plugin/virtual-loader/griffel.css
+++ /dev/null
@@ -1,2 +0,0 @@
-/* This is a noop file for extracted CSS source to point to */
-/* Webpack requires a file to exist on disk for virtual source files */
diff --git a/packages/webpack-extraction-plugin/virtual-loader/index.js b/packages/webpack-extraction-plugin/virtual-loader/index.js
index 48d51b1..9b80d92 100644
--- a/packages/webpack-extraction-plugin/virtual-loader/index.js
+++ b/packages/webpack-extraction-plugin/virtual-loader/index.js
@@ -1,14 +1,11 @@
-const { URLSearchParams } = require('url');
-
 /**
- * @this {import('webpack').LoaderContext<unknown>}
+ * @this {import('webpack').LoaderContext<{ style?: string }>}
  * @return {String}
  */
 function virtualLoader() {
-  const query = new URLSearchParams(this.resourceQuery);
-  const styleRule = query.get('style');
+  const { style = '' } = this.getOptions();
 
-  return styleRule ?? '';
+  return style;
 }
 
 module.exports = virtualLoader;


Test patch:
diff --git a/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.test.ts b/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.test.ts
index d504070..9bee050 100644
--- a/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.test.ts
+++ b/packages/webpack-extraction-plugin/src/babelPluginStripGriffelRuntime.test.ts
@@ -15,9 +15,6 @@ pluginTester({
       plugins: ['typescript'],
     },
   },
-  pluginOptions: {
-    resourceDirectory: process.cwd(),
-  },
   formatResult: code =>
     prettierFormatter(code, {
       config: {