diff --git a/.gitignore b/.gitignore
index 2700b7a3..38443a48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@ dist-ssr
.npmrc
build
+presets
+transforms
diff --git a/cssTransform.js b/cssTransform.js
new file mode 100644
index 00000000..1895471d
--- /dev/null
+++ b/cssTransform.js
@@ -0,0 +1,76 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+require('path');
+require('camelcase');
+
+function getRelativeFilename(filename) {
+ return filename.split(process.cwd())[1];
+}
+function processCss(src, filename) {
+ if (filename.endsWith('.module.css')) {
+ return processCSSModules(src, filename);
+ }
+ const relativeFilename = getRelativeFilename(filename);
+ // Transform to a javascript module that load a tag to the page.
+ return `const relativeCssPath = "${relativeFilename}";
+ const link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.href = relativeCssPath;
+ document.body.appendChild(link);
+
+ module.exports = JSON.stringify(relativeCssPath);`;
+}
+// TODO: MEDIUM PRIORITY To research about getCacheKey
+// Reference:
+// - https://jestjs.io/docs/code-transformation#writing-custom-transformers
+// - https://github.com/swc-project/jest/blob/17cf883b46c050a485975d8ce96a05277cf6032f/index.ts#L37-L52
+// const cacheKeyFunction = createCacheKey();
+// export function getCacheKey(src: string, filename: string, ...rest): string {
+// const baseCacheKey = cacheKeyFunction(src, filename, ...rest);
+// return crypto.createHash('md5').update(baseCacheKey).digest('hex');
+// }
+// We cannot create async transformer if we are using CommonJS
+// ( Reference: https://github.com/facebook/jest/issues/11081#issuecomment-791259034
+// https://github.com/facebook/jest/issues/11458
+// Also, there is a inconsistency in jest docs about should `process` be required
+// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
+// A transformer must be an object with at least a process function
+// https://jestjs.io/docs/code-transformation#writing-custom-transformers
+// As can be seen, only process or processAsync is mandatory to implement)
+// We can use that if we opt-in to ESM. But it's not common use case right now (2022)
+// So our approach is making CSS Modules a "CSS-in-JS" solution.
+// CSS Modules will be compiled at run time then inject to the document.body
+// One notable note is that `postcss-modules` is an async postcss plugin
+// so we need to use `postcss-modules.sync`, with function `sync()`
+function processCSSModules(src, filename) {
+ return `
+const postcss = require('postcss');
+const CSSModulesSync = require('postcss-modules-sync').default;
+const cssSrc = ${JSON.stringify(src)};
+
+let exportedTokens = {};
+
+const result = postcss(
+ CSSModulesSync({
+ getJSON: (tokens) => {
+ exportedTokens = tokens;
+ },
+ }),
+)
+.process(cssSrc, { from: ${JSON.stringify(filename)} })
+
+const style = document.createElement('style');
+style.type = 'text/css';
+style.appendChild(document.createTextNode(result.css));
+document.body.appendChild(style);
+
+module.exports = exportedTokens`;
+}
+
+function process$1(src, filename) {
+ return processCss(src, filename);
+}
+
+exports.process = process$1;
diff --git a/examples/vite-react/jest.config.js b/examples/vite-react/jest.config.js
index c88ceb95..dd4ddfe3 100644
--- a/examples/vite-react/jest.config.js
+++ b/examples/vite-react/jest.config.js
@@ -11,9 +11,9 @@ module.exports = {
modulePaths: ['/src'],
transform: {
'^.+\\.(ts|js|tsx|jsx)$': '@swc/jest',
- '^.+\\.css$': '/config/jest/cssTransform.js',
+ '^.+\\.css$': 'jest-preview/transforms/css',
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)':
- '/config/jest/fileTransform.js',
+ 'jest-preview/transforms/file',
},
transformIgnorePatterns: [
'[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
diff --git a/examples/vite-react/package.json b/examples/vite-react/package.json
index 77b14e52..d205071b 100644
--- a/examples/vite-react/package.json
+++ b/examples/vite-react/package.json
@@ -8,6 +8,7 @@
"preview": "vite preview",
"jest-preview": "jest-preview",
"test": "NODE_ENV=test jest --watch",
+ "test:nc": "npm run test -- --no-cache",
"test:debug": "npm-run-all -p test jest-preview"
},
"dependencies": {
diff --git a/package.json b/package.json
index 7f50197f..20d5715d 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,8 @@
},
"files": [
"dist",
- "server"
+ "server",
+ "transforms"
],
"scripts": {
"dev": "vite",
diff --git a/src/preconfig/cssTransform.ts b/src/preconfigTransform/css.ts
similarity index 55%
rename from src/preconfig/cssTransform.ts
rename to src/preconfigTransform/css.ts
index 55194ede..8bb1edee 100644
--- a/src/preconfig/cssTransform.ts
+++ b/src/preconfigTransform/css.ts
@@ -2,6 +2,7 @@
import { processCss } from '../transform';
-export function process(src: string, filename: string) {
+function process(src: string, filename: string) {
return processCss(src, filename);
}
+export default { process };
diff --git a/src/preconfigTransform/file.ts b/src/preconfigTransform/file.ts
new file mode 100644
index 00000000..236ea502
--- /dev/null
+++ b/src/preconfigTransform/file.ts
@@ -0,0 +1,8 @@
+'use strict';
+
+import { processFile } from '../transform';
+
+function process(src: string, filename: string) {
+ return processFile(src, filename);
+}
+export default { process };
diff --git a/src/preconfigTransform/fileCRA.ts b/src/preconfigTransform/fileCRA.ts
new file mode 100644
index 00000000..1da04089
--- /dev/null
+++ b/src/preconfigTransform/fileCRA.ts
@@ -0,0 +1,8 @@
+'use strict';
+
+import { processFileCRA } from '../transform';
+
+function process(src: string, filename: string) {
+ return processFileCRA(src, filename);
+}
+export default { process };