Skip to content

Commit

Permalink
add support for multiple bundlers and module systems
Browse files Browse the repository at this point in the history
  • Loading branch information
tusharsnx committed Jun 10, 2024
1 parent 4ef7549 commit 6c79999
Show file tree
Hide file tree
Showing 10 changed files with 1,559 additions and 2,247 deletions.
14 changes: 5 additions & 9 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import type { InitialOptionsTsJest } from "ts-jest";
import type { Config } from "jest";

module.exports = <InitialOptionsTsJest>{
const config: Config = {
preset: "ts-jest/presets/default-esm",
testEnvironment: "node",
globals: {
"ts-jest": {
// ts-jest needs to be told to use ESM. Choosing
// an esm preset for ts-jest doesn't imply useEsm (??).
useESM: true,
},
},
extensionsToTreatAsEsm: [".ts"],
};

export default config;
3,561 changes: 1,398 additions & 2,163 deletions package-lock.json

Large diffs are not rendered by default.

40 changes: 26 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
"author": "Tushar Singh",
"repository": "github:tusharsnn/jsx-css-module-transforms",
"type": "module",
"module": "dist/plugin.js",
"types": "dist/plugin.d.ts",
"main": "dist/plugin.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"main": "dist/index.cjs",
"exports": {
".": {
"import": "./dist/plugin.js",
"require": "./dist/plugin.cjs",
"types": "./dist/plugin.d.ts"
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"files": [
Expand All @@ -23,21 +23,33 @@
"module-classname-transforms"
],
"scripts": {
"build": "tsup",
"test": "npm run build && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --verbose",
"test:cov": "npm run build && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --verbose --coverage",
"dev": "tsup --watch"
"build": "NODE_ENV=production npx tsup-node --config tsup.build.config.ts",
"dev": "npx tsup-node --watch",
"dev:nowatch": "npx tsup-node",
"test": "npm run dev:nowatch && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --verbose",
"test:cov": "npm run dev:nowatch && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --verbose --coverage"
},
"dependencies": {
"@babel/core": "^7.24.3",
"chalk": "^4.1.2"
"chalk": "^4.1.2",
"unplugin": "^1.10.1"
},
"peerDependencies": {
"@babel/plugin-syntax-jsx": "^7.24.1",
"webpack": "^5.91.0"
},
"peerDependenciesMeta": {
"webpack": {
"optional": true
}
},
"devDependencies": {
"@babel/plugin-syntax-jsx": "^7.17.12",
"@types/babel__core": "^7.20.5",
"@types/jest": "^27.5.0",
"jest": "^28.1.0",
"ts-jest": "^28.0.2",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.2",
"jest": "^29.7.0",
"ts-jest": "^29.1.4",
"tsup": "^8.0.2",
"typescript": "^4.9.5"
}
Expand Down
33 changes: 33 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { transformAsync } from "@babel/core";
import { createWebpackPlugin } from "unplugin";
import type { UnpluginOptions } from "unplugin";
import plugin from "./plugin.js";
import { CSSModuleError } from "./utils.js";

function unpluginFactory(): UnpluginOptions {
return {
name: "jsx-css-module-transforms",

transformInclude(id) {
const result = /\.tsx?$/i.test(id);
return result;
},

async transform(code, id) {
// babel's transformSync cannot be used with ESM based plugin
const result = await transformAsync(code, {
filename: id,
plugins: ["@babel/plugin-syntax-jsx", plugin],
sourceMaps: process.env.NODE_ENV == "production" ? false : "inline",
});

if (!result?.code) {
throw new CSSModuleError(`Could not transform ${id}`);
}

return result.code;
},
};
}

export default createWebpackPlugin(unpluginFactory);
2 changes: 1 addition & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function JSXAttribute(path: NodePath<t.JSXAttribute>, state: PluginPass) {
path.skip();
}

function API({ types: t }: typeof babel): PluginObj<PluginPass> {
function API(): PluginObj<PluginPass> {
/**
* Sets up the initial state of the plugin
*/
Expand Down
84 changes: 42 additions & 42 deletions tests/transforms.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import babel from "@babel/core";
import API from "../dist/plugin.js";
import { CSSModuleError } from "../dist/utils.js";
import API from "../dev/plugin.js";
import { CSSModuleError } from "../dev/utils.js";

async function runWithBabel(source: string) {
let transformed = await babel.transformAsync(source, {
Expand All @@ -13,41 +13,41 @@ describe("single imports", () => {
test("default module", async () => {
let source = `import "./foo.module.scss"`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import _style from \\"./foo.module.scss\\";"`);
expect(code).toMatchInlineSnapshot(`"import _style from "./foo.module.scss";"`);

source = `import "./foo.module.css"`;
code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import _style from \\"./foo.module.css\\";"`);
expect(code).toMatchInlineSnapshot(`"import _style from "./foo.module.css";"`);
});

test("with specifier", async () => {
let source = `import style from "./foo.module.scss"`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import style from \\"./foo.module.scss\\";"`);
expect(code).toMatchInlineSnapshot(`"import style from "./foo.module.scss";"`);

source = `import style from "./foo.module.css"`;
code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import style from \\"./foo.module.css\\";"`);
expect(code).toMatchInlineSnapshot(`"import style from "./foo.module.css";"`);
});

test("with specifier (ignore names)", async () => {
let source = `import style from "./foo.module.scss:m1"`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import style from \\"./foo.module.scss\\";"`);
expect(code).toMatchInlineSnapshot(`"import style from "./foo.module.scss";"`);

source = `import style from "./foo.module.css:m1"`;
code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import style from \\"./foo.module.css\\";"`);
expect(code).toMatchInlineSnapshot(`"import style from "./foo.module.css";"`);
});

test("with named-module", async () => {
let source = `import "./foo.module.scss:m1"`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import _m from \\"./foo.module.scss\\";"`);
expect(code).toMatchInlineSnapshot(`"import _m from "./foo.module.scss";"`);

source = `import "./foo.module.css:m1"`;
code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`"import _m from \\"./foo.module.css\\";"`);
expect(code).toMatchInlineSnapshot(`"import _m from "./foo.module.css";"`);
});

test("multiple imports on single module", async () => {
Expand Down Expand Up @@ -77,8 +77,8 @@ describe("imports multiple module", () => {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import _m from \\"./module1.module.css\\";
import _m2 from \\"./module2.module.css\\";"
"import _m from "./module1.module.css";
import _m2 from "./module2.module.css";"
`);
});

Expand All @@ -97,8 +97,8 @@ import _m2 from \\"./module2.module.css\\";"
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import style from \\"./module1.module.css\\";
import style1 from \\"./module2.module.css\\";"
"import style from "./module1.module.css";
import style1 from "./module2.module.css";"
`);
});

Expand All @@ -120,9 +120,9 @@ describe("different kinds together", () => {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import style from \\"./module1.module.css\\";
import _m from \\"./module2.module.css\\";
import _style from \\"./module3.module.css\\";"
"import style from "./module1.module.css";
import _m from "./module2.module.css";
import _style from "./module3.module.css";"
`);
});

Expand Down Expand Up @@ -156,9 +156,9 @@ describe("jsx with single css-module", () => {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import _style from \\"./component.module.css\\";
"import _style from "./component.module.css";
function Component() {
return <h1 className={\`\${_style[\\"foo-bar\\"]} \${_style[\\"baz\\"]}\`}></h1>;
return <h1 className={\`\${_style["foo-bar"]} \${_style["baz"]}\`}></h1>;
}"
`);
});
Expand All @@ -173,9 +173,9 @@ function Component() {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import style from \\"./component.module.css\\";
"import style from "./component.module.css";
function Component() {
return <h1 className={\`\${style[\\"foo-bar\\"]} \${style[\\"baz\\"]}\`}></h1>;
return <h1 className={\`\${style["foo-bar"]} \${style["baz"]}\`}></h1>;
}"
`);
});
Expand All @@ -190,9 +190,9 @@ function Component() {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import _m from \\"./component.module.css\\";
"import _m from "./component.module.css";
function Component() {
return <h1 className={\`\${_m[\\"foo-bar\\"]} \${_m[\\"baz\\"]}\`}></h1>;
return <h1 className={\`\${_m["foo-bar"]} \${_m["baz"]}\`}></h1>;
}"
`);
});
Expand Down Expand Up @@ -221,10 +221,10 @@ describe("jsx with multiple modules", () => {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import \\"./component.css\\";
import \\"./layout.css\\";
"import "./component.css";
import "./layout.css";
function component() {
return <h1 className=\\"foo-bar baz\\"></h1>;
return <h1 className="foo-bar baz"></h1>;
}"
`);
});
Expand All @@ -240,10 +240,10 @@ function component() {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import style from \\"./component.module.css\\";
import layout from \\"./layout.module.css\\";
"import style from "./component.module.css";
import layout from "./layout.module.css";
function Component() {
return <h1 className={\`\${layout[\\"foo-bar\\"]} \${style[\\"baz\\"]}\`}></h1>;
return <h1 className={\`\${layout["foo-bar"]} \${style["baz"]}\`}></h1>;
}"
`);
});
Expand All @@ -259,10 +259,10 @@ function Component() {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import _style from \\"./component.module.css\\";
import _layout from \\"./layout.module.css\\";
"import _style from "./component.module.css";
import _layout from "./layout.module.css";
function Component() {
return <h1 className={\`\${_layout[\\"foo-bar\\"]} \${_style[\\"baz\\"]}\`}></h1>;
return <h1 className={\`\${_layout["foo-bar"]} \${_style["baz"]}\`}></h1>;
}"
`);
});
Expand Down Expand Up @@ -309,12 +309,12 @@ describe("jsx with multiple kinds of module", () => {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import style from \\"./component.module.css\\";
import layout from \\"./layout.module.css\\";
import _altLayout from \\"./layout2.module.css\\";
"import style from "./component.module.css";
import layout from "./layout.module.css";
import _altLayout from "./layout2.module.css";
function Component() {
return <div className={\`\${layout[\\"grid-1\\"]} \${_altLayout[\\"col-3\\"]}\`}>
<h1 className={\`\${style[\\"clr-green\\"]}\`}></h1>
return <div className={\`\${layout["grid-1"]} \${_altLayout["col-3"]}\`}>
<h1 className={\`\${style["clr-green"]}\`}></h1>
</div>;
}"
`);
Expand All @@ -336,12 +336,12 @@ function Component() {
`;
let code = await runWithBabel(source);
expect(code).toMatchInlineSnapshot(`
"import style from \\"./component.module.css\\";
import layout from \\"./layout.module.css\\";
import _altLayout from \\"./layout2.module.css\\";
"import style from "./component.module.css";
import layout from "./layout.module.css";
import _altLayout from "./layout2.module.css";
function Component() {
return <div className={\`\${layout[\\"grid-1\\"]} \${_altLayout[\\"col-3\\"]}\`}>
<h1 className={\`bg-primary \${style[\\"clr-green\\"]}\`}></h1>
return <div className={\`\${layout["grid-1"]} \${_altLayout["col-3"]}\`}>
<h1 className={\`bg-primary \${style["clr-green"]}\`}></h1>
</div>;
}"
`);
Expand Down
4 changes: 2 additions & 2 deletions tests/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as t from "@babel/types";

import { splitClsName, shouldTransform, CSSModuleError } from "../dist/utils.js";
import { createModuleMemberExpression } from "../dist/transforms.js";
import { splitClsName, shouldTransform, CSSModuleError } from "../dev/utils.js";
import { createModuleMemberExpression } from "../dev/transforms.js";

// testing splitModuleName
describe("split string into module and classnames", () => {
Expand Down
18 changes: 13 additions & 5 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@
"forceConsistentCasingInFileNames": true,
"module": "Node16",
"moduleResolution": "Node16",
"target": "es6",
// without this, jest/ts-jest may hang and never finish
"allowJs": true,
"target": "ES6",
"esModuleInterop": true,
"sourceMap": true,
"outDir": "./dist"
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"isolatedModules": true,
// These options are controlled by the tsup config
"sourceMap": false,
"declaration": false,
"outDir": ""
},
"include": [
"./src/**/*.ts",
],
"exclude": [
"node_modules",
"dist",
]
}
22 changes: 22 additions & 0 deletions tsup.build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineConfig } from "tsup";

export default defineConfig({
clean: true,
dts: true,

// Bundle optimizations
treeshake: false, // When true, generates broken commonjs code
splitting: false,
minify: false,

// Transforms esm's `import.meta.url` to its cjs alternative and cjs's `__dirname` to its esm alternative
shims: true,

// Prod build options
entry: ["src/index.ts"],
outDir: "dist",
format: ["cjs", "esm"],
cjsInterop: true,
sourcemap: false,
bundle: true,
});
Loading

0 comments on commit 6c79999

Please sign in to comment.