Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/vite-plugin-commonjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export default {
- `include: string[]`
Dependencies that only need to be transform.

- `addNamedExports: boolean`
add named exports.

### CommonJS module in node_modules
```js
import { esbuildCommonjs } from '@originjs/vite-plugin-commonjs'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`transform named exports 1`] = `
"var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var require_stdin = __commonJS({
\\"<stdin>\\"(exports, module) {
const a = \\"a\\";
const obj = {
o1: 1,
o2: 2
};
module.exports = {
a,
b: \\"b\\",
...obj
};
exports.c = \\"c\\";
}
});

var __named_exports_for_vite = require_stdin();

var __named_exports_for_vite__a = __named_exports_for_vite['a'];
var __named_exports_for_vite__b = __named_exports_for_vite['b'];
var __named_exports_for_vite__o1 = __named_exports_for_vite['o1'];
var __named_exports_for_vite__o2 = __named_exports_for_vite['o2'];
var __named_exports_for_vite__c = __named_exports_for_vite['c'];

export {__named_exports_for_vite__a as a,__named_exports_for_vite__b as b,__named_exports_for_vite__o1 as o1,__named_exports_for_vite__o2 as o2,__named_exports_for_vite__c as c};

export default __named_exports_for_vite;

"
`;
26 changes: 25 additions & 1 deletion packages/vite-plugin-commonjs/__tests__/transform.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { transformRequire, isCommonJS } from "../src/lib";
import { transformRequire, isCommonJS, transformCommonJS } from "../src/lib";

test('transform require', () => {
//general require
Expand Down Expand Up @@ -67,6 +67,30 @@ test('isCommonJS', () => {
expect(isCommonJS(`exports['some key'] = 1`)).toBeTruthy();
});

test('transform named exports', () => {

let code = `
const a = 'a';

const obj = {
o1: 1,
o2: 2
};

module.exports = {
a,
b: 'b',
...obj
};

exports.c = 'c';
`;

const transformResult = transformCommonJS(code, true).code;
expect(transformResult).toMatch(/export {.*__named_exports_for_vite__a as a,.*}/);
expect(transformResult).toMatchSnapshot();
});

test('Both url and comments are present', () => {
//singleline comments
let code = `dosomething () {
Expand Down
1 change: 1 addition & 0 deletions packages/vite-plugin-commonjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"homepage": "https://github.com/originjs/vite-plugins/tree/main/packages/vite-plugin-commonjs",
"dependencies": {
"cjs-esm-exports": "^0.6.1",
"esbuild": "^0.14.14"
},
"devDependencies": {
Expand Down
9 changes: 5 additions & 4 deletions packages/vite-plugin-commonjs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { transformSync, TransformResult } from "esbuild";
import { transformRequire, isCommonJS } from "./lib";
import { TransformResult } from "esbuild";
import { transformRequire, transformCommonJS, isCommonJS } from "./lib";
import * as fs from "fs";
import { Plugin } from "vite";
import createFilter from "./filter";
Expand All @@ -8,10 +8,11 @@ export type Options = {
include?: string | string[] | undefined;
exclude?: string | string[] | undefined;
skipPreBuild?: boolean;
addNamedExports?: boolean;
};

export function viteCommonjs(
options: Options = { skipPreBuild: false }
options: Options = { skipPreBuild: false, addNamedExports: false }
): Plugin {
const filter = createFilter(options.include, options.exclude);
return {
Expand All @@ -28,7 +29,7 @@ export function viteCommonjs(
let result = transformRequire(code, id);

if (id.indexOf("/node_modules/.vite/") == -1 && isCommonJS(code)) {
return transformSync(result.code, { format: "esm" });
return transformCommonJS(result.code, options.addNamedExports);
}

if (result.replaced) {
Expand Down
53 changes: 52 additions & 1 deletion packages/vite-plugin-commonjs/src/lib.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { parse as parseCjs } from 'cjs-esm-exports';
import { transformSync } from 'esbuild';

const commonJSRegex: RegExp = /\b(module\.exports|exports\.\w+|exports\s*=\s*|exports\s*\[.*\]\s*=\s*)/;
const requireRegex: RegExp = /(?<!\.)\b_{0,2}require\s*\(\s*(["'].*?["'])\s*\)/g;
const IMPORT_STRING_PREFIX: String = "__require_for_vite";
Expand Down Expand Up @@ -50,6 +53,54 @@ export function isCommonJS(code: string): boolean {
return commonJSRegex.test(code);
}

export function transformCommonJS(code: string, addNamedExports = false) {
const transformResult = transformSync(code, { format: "esm" });

if (!addNamedExports) {
return transformResult;
}

const esmCode = transformResult.code;
const defaultExportRegex = /export default (.*?);/;
const defaultExport = esmCode.match(defaultExportRegex)?.[1];

if (!defaultExport) {
return transformResult;
}

const { exports } = parseCjs('', code);
if (!exports || !exports.length) {
return transformResult;
}

const namedKey = '__named_exports_for_vite';
const namedExportsMap: Record<string, string> = exports.reduce(
(map: Record<string, string>, key: string) => {
map[key] = `${namedKey}['${key}']`;
return map;
},
{},
);
const namedKeys = Object.keys(namedExportsMap);

const namedExportsCode = `
var ${namedKey} = ${defaultExport};

${namedKeys.map(key => {
return `var ${namedKey}__${key} = ${namedExportsMap[key]};`
}).join('\n')}

export {${namedKeys.map(key => `${namedKey}__${key} as ${key}`).join(',')}};

export default ${namedKey};
`;

return {
...transformResult,
code: esmCode.replace(defaultExportRegex, namedExportsCode),
};
}

function removeComments(
code: string,
exp: RegExp,
Expand Down Expand Up @@ -86,4 +137,4 @@ function isString(text: string) {
} catch (err) {
return false;
}
}
}