Skip to content

Commit

Permalink
add esbuild commonjs support
Browse files Browse the repository at this point in the history
  • Loading branch information
flyfishzy committed Jun 10, 2021
1 parent 1c2fc45 commit b09c5db
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ dist
# TernJS port file
.tern-port

packages/vite-plugin-commonjs/lib
lib
3 changes: 1 addition & 2 deletions packages/vite-plugin-commonjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
},
"main": "lib/index.js",
"files": [
"src",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/originjs/vite-plugins.git"
},
"keywords": [
"vite",
"vite-plugin",
"commonjs"
],
"author": "[email protected]",
Expand Down
121 changes: 51 additions & 70 deletions packages/vite-plugin-commonjs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,61 @@
import { transformSync, TransformResult } from "esbuild";
import { transformRequire, isCommonJS } from "./lib";
import * as fs from "fs";
import { Plugin } from "vite";
import { createFilter } from "@rollup/pluginutils";

const commonJSRegex: RegExp = /\b(module\.exports|exports\.\w+|exports\s*=\s*)/;
const requireRegex: RegExp = /require\(([\'|\"].*[\'|\"])\)/g;
const IMPORT_STRING_PREFIX: String = "__require_for_vite";

type Options = {
include?: string | RegExp | string[] | RegExp[] | undefined;
exclude?: string | RegExp | string[] | RegExp[] | undefined;
include?: string | RegExp | string[] | RegExp[] | undefined;
exclude?: string | RegExp | string[] | RegExp[] | undefined;
};

export default (options: Options = {}): Plugin => {
const filter = createFilter(options.include, options.exclude);

return {
name: "originjs:commonjs",
apply: "serve",
transform(code: string, id: string): TransformResult {
if (!filter(id)) {
return null;
}

const requireMatches = code.matchAll(requireRegex);
let importsString = "";
let packageName = "";
for (let item of requireMatches) {
if (!isString(item[1])) {
console.warn(`Not supported dynamic import, file:${id}`);
continue;
}

packageName = `${IMPORT_STRING_PREFIX}_${randomString(6)}`;
importsString += `import * as ${packageName} from ${item[1]};\n`;
code = code.replace(item[0], packageName);
}

if (importsString) {
code = importsString + code;
}

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

if (importsString) {
return {
code,
map: null,
warnings: null,
};
}

return null;
},
};
};

function isCommonJS(code: string): Boolean {
return commonJSRegex.test(code);
}

function randomString(length: number): string {
const code: string =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
let result: string = "";
for (let index = 0; index < length; index++) {
result += code[Math.floor(Math.random() * code.length)];
export function viteCommonjs(options: Options = {}): Plugin {
const filter = createFilter(options.include, options.exclude);
return {
name: "originjs:commonjs",
apply: "serve",
transform(code: string, id: string): TransformResult {
if (!filter(id)) {
return null;
}
let result = transformRequire(code, id);
if (id.indexOf("/node_modules/.vite/") == -1 && isCommonJS(code)) {
return transformSync(result.code, { format: "esm" });
}

if (result.replaced) {
return {
code: result.code,
map: null,
warnings: null,
}
}
return null;
}
return result;
}
}
};

function isString(text: string) {
try {
return typeof eval(text) === "string";
} catch (err) {
return false;
export function esbuildCommonjs(includes: string[] = []) {
return {
name: "originjs:commonjs",
setup(build) {
build.onLoad(
{
filter: new RegExp('(' + includes.join('|') + ').*\.js'),
namespace: 'file'
},
async ({ path: id }) => {
const code = fs.readFileSync(id).toString();
let result = transformRequire(code, id);
if (result.replaced) {
return {
contents: result.code,
loader: 'js'
}
}
return null
}
)
}
}
}
};
55 changes: 55 additions & 0 deletions packages/vite-plugin-commonjs/src/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const commonJSRegex: RegExp = /\b(module\.exports|exports\.\w+|exports\s*=\s*)/;
const requireRegex: RegExp = /require\s*\((["'].*["'])\)/g;
const IMPORT_STRING_PREFIX: String = "__require_for_vite";

export interface TransformRequireResult {
code: string;
replaced: boolean;
}

export function transformRequire(code: string, id: string):TransformRequireResult {
const requireMatches = code.matchAll(requireRegex);
let importsString = "";
let packageName = "";
let replaced = false;
for (let item of requireMatches) {
if (!isString(item[1])) {
console.warn(`Not supported dynamic import, file:${id}`);
continue;
}
replaced = true;
packageName = `${IMPORT_STRING_PREFIX}_${randomString(6)}`;
importsString += `import * as ${packageName} from ${item[1]};\n`;
code = code.replace(item[0], packageName);
}

if (replaced) {
code = importsString + code;
}
return {
replaced,
code
}
}

export function isCommonJS(code: string): boolean {
return commonJSRegex.test(code);
}

function randomString(length: number): string {
const code: string =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
let result: string = "";
for (let index = 0; index < length; index++) {
result += code[Math.floor(Math.random() * code.length)];
}
return result;
}

function isString(text: string) {
try {
return typeof eval(text) === "string";
} catch (err) {
return false;
}
}
2 changes: 1 addition & 1 deletion packages/vite-plugin-require-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"url": "git+https://github.com/originjs/vite-plugins.git"
},
"keywords": [
"vite",
"vite-plugin",
"require.context"
],
"author": "Peter Lee",
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"declaration": true,
"outDir": "lib",
"target": "esnext",
"module": "esnext",
"module": "commonjs",
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node",
Expand Down

0 comments on commit b09c5db

Please sign in to comment.