Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: check if js needs compilation #365

Merged
merged 76 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
4103b71
test: remove old node versions
privatenumber Sep 25, 2023
189e684
delete deprecated loader code
privatenumber Sep 25, 2023
6ac8076
wip
privatenumber Sep 25, 2023
dd73218
wip
privatenumber Sep 25, 2023
33cb8bf
wip
privatenumber Oct 30, 2023
f0376ca
wip
privatenumber Oct 31, 2023
bd4d4f8
wip
privatenumber Oct 31, 2023
c018bf1
wip
privatenumber Oct 31, 2023
343ea81
wip
privatenumber Oct 31, 2023
a77c204
wip
privatenumber Oct 31, 2023
80d0825
wip
privatenumber Oct 31, 2023
78c488b
wip
privatenumber Oct 31, 2023
45cedfd
wip
privatenumber Oct 31, 2023
c552045
wip
privatenumber Oct 31, 2023
5da4098
wip
privatenumber Oct 31, 2023
60a6904
Merge branch 'next' of github.com:esbuild-kit/tsx into drop-node-vers…
privatenumber Oct 31, 2023
391dae4
wip
privatenumber Oct 31, 2023
54d6612
wip
privatenumber Oct 31, 2023
f6b2473
wip
privatenumber Oct 31, 2023
09db06f
wip
privatenumber Oct 31, 2023
b0a16ef
wip
privatenumber Oct 31, 2023
2d27fbd
wip
privatenumber Oct 31, 2023
daf4274
wip
privatenumber Oct 31, 2023
081dcac
wip
privatenumber Oct 31, 2023
d909d54
wip
privatenumber Nov 1, 2023
0a8a9dd
wip
privatenumber Nov 1, 2023
b61792e
wip
privatenumber Nov 1, 2023
faef28a
wip
privatenumber Nov 1, 2023
53f13fd
wip
privatenumber Nov 1, 2023
64d32c3
wip
privatenumber Nov 1, 2023
5565210
wip
privatenumber Nov 1, 2023
e87614f
wip
privatenumber Nov 1, 2023
e43dd01
wip
privatenumber Nov 1, 2023
26eadf6
wip
privatenumber Nov 1, 2023
f6f99e1
wip
privatenumber Nov 1, 2023
17b2dd9
wip
privatenumber Nov 1, 2023
8aff097
wip
privatenumber Nov 1, 2023
9c14f0d
wip
privatenumber Nov 1, 2023
c8e390e
wip
privatenumber Nov 1, 2023
87030fc
wip
privatenumber Nov 1, 2023
573b30e
wip
privatenumber Nov 1, 2023
6144965
wip
privatenumber Nov 2, 2023
449915d
engines
privatenumber Nov 3, 2023
7621762
Merge branch 'drop-node-versions' into refactor-tests
privatenumber Nov 5, 2023
6a162ae
wip
privatenumber Nov 5, 2023
bc05b0f
wip
privatenumber Nov 5, 2023
72e8e32
wip
privatenumber Nov 5, 2023
1182ff2
wip
privatenumber Nov 5, 2023
07097fd
wip
privatenumber Nov 5, 2023
ae4e5f5
wip
privatenumber Nov 5, 2023
21d0592
wip
privatenumber Nov 5, 2023
aabaacc
wip
privatenumber Nov 5, 2023
b8592c6
wip
privatenumber Nov 5, 2023
b16dc15
wip
privatenumber Nov 5, 2023
180367c
wip
privatenumber Nov 5, 2023
32f53a4
wip
privatenumber Nov 5, 2023
b0d5e21
perf: check if js needs compilation
privatenumber Nov 6, 2023
3d6b56d
wip
privatenumber Nov 6, 2023
fc46f9f
wip
privatenumber Nov 6, 2023
d51c01f
wip
privatenumber Nov 6, 2023
4b76cf3
Merge branch 'refactor-tests' into cjs-compile-esm-check
privatenumber Nov 6, 2023
f90f342
feat: drop support for outdated Node.js versions (#324)
privatenumber Nov 7, 2023
1f61dc5
Merge branch 'next' into refactor-tests
privatenumber Nov 7, 2023
e0893de
wip
privatenumber Nov 7, 2023
4a38ab2
Merge branch 'refactor-tests' of github.com:esbuild-kit/tsx into refa…
privatenumber Nov 7, 2023
18e3e8b
wip
privatenumber Nov 7, 2023
3b1a07d
wip
privatenumber Nov 8, 2023
b56adf6
wip
privatenumber Nov 8, 2023
8c17fa1
test: refactor to smoke test (#360)
privatenumber Nov 8, 2023
50a94b6
Merge commit 'b56adf6' into cjs-compile-esm-check
privatenumber Nov 9, 2023
5745007
Merge commit '8c17fa1' into cjs-compile-esm-check
privatenumber Nov 9, 2023
0e13f69
Merge branch 'next' of github.com:esbuild-kit/tsx into cjs-compile-es…
privatenumber Nov 9, 2023
36b8b72
Merge branch 'cjs-compile-esm-check' of github.com:esbuild-kit/tsx in…
privatenumber Nov 9, 2023
2a08e95
wip
privatenumber Nov 9, 2023
1e01c8f
Merge branch 'next' into cjs-compile-esm-check
privatenumber Nov 9, 2023
f653a8c
Merge branch 'next' into cjs-compile-esm-check
privatenumber Nov 9, 2023
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
36 changes: 22 additions & 14 deletions src/cjs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { TransformOptions } from 'esbuild';
import { installSourceMapSupport } from '../source-map';
import { transformSync, transformDynamicImport } from '../utils/transform';
import { resolveTsPath } from '../utils/resolve-ts-path';
import { isESM } from '../utils/esm-pattern';

const isRelativePathPattern = /^\.{1,2}\//;
const isTsFilePatten = /\.[cm]?tsx?$/;
Expand All @@ -33,44 +34,51 @@ const applySourceMap = installSourceMapSupport();
const extensions = Module._extensions;
const defaultLoader = extensions['.js'];

const transformExtensions = [
'.js',
'.cjs',
const typescriptExtensions = [
'.cts',
'.mjs',
'.mts',
'.ts',
'.tsx',
'.jsx',
];

const transformExtensions = [
'.js',
'.cjs',
'.mjs',
];

const transformer = (
module: Module,
filePath: string,
) => {
const shouldTransformFile = transformExtensions.some(extension => filePath.endsWith(extension));
if (!shouldTransformFile) {
return defaultLoader(module, filePath);
}

/**
* For tracking dependencies in watch mode
*/
// For tracking dependencies in watch mode
if (process.send) {
process.send({
type: 'dependency',
path: filePath,
});
}

let code = fs.readFileSync(filePath, 'utf8');
const transformTs = typescriptExtensions.some(extension => filePath.endsWith(extension));
const transformJs = transformExtensions.some(extension => filePath.endsWith(extension));
if (!transformTs && !transformJs) {
return defaultLoader(module, filePath);
}

let code = fs.readFileSync(filePath, 'utf8');
if (filePath.endsWith('.cjs')) {
// Contains native ESM check
const transformed = transformDynamicImport(filePath, code);
if (transformed) {
code = applySourceMap(transformed, filePath);
}
} else {
} else if (
transformTs

// CommonJS file but uses ESM import/export
|| isESM(code)
) {
const transformed = transformSync(
code,
filePath,
Expand Down
5 changes: 5 additions & 0 deletions src/esm/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@

const isRelativePathPattern = /^\.{1,2}\//;

export const resolve: resolve = async function (

Check warning on line 158 in src/esm/loaders.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unexpected unnamed async function

Check warning on line 158 in src/esm/loaders.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Async function has a complexity of 22. Maximum allowed is 10
specifier,
context,
defaultResolve,
Expand Down Expand Up @@ -243,11 +243,15 @@
}
};

export const load: LoadHook = async function (

Check warning on line 246 in src/esm/loaders.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unexpected unnamed async function
url,
context,
defaultLoad,
) {
/*
Filter out node:*
Maybe only handle files that start with file://
*/
if (sendToParent) {
sendToParent({
type: 'dependency',
Expand All @@ -264,6 +268,7 @@

const loaded = await defaultLoad(url, context);

// CommonJS and Internal modules (e.g. node:*)
if (!loaded.source) {
return loaded;
}
Expand Down
36 changes: 36 additions & 0 deletions src/utils/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const time = <Argument>(
name: string,
_function: (...args: Argument[]) => unknown,
) => function (
this: unknown,
...args: Argument[]
) {
const timeStart = Date.now();
const logTimeElapsed = () => {
const elapsed = Date.now() - timeStart;

if (elapsed > 10) {
// console.log({
// name,
// args,
// elapsed,
// });
}
};

const result = Reflect.apply(_function, this, args);
if (
result
&& typeof result === 'object'
&& 'then' in result
) {
(result as Promise<unknown>).then(
logTimeElapsed,
// Ignore error in this chain
() => {},
);
} else {
logTimeElapsed();
}
return result;
};
24 changes: 24 additions & 0 deletions src/utils/esm-pattern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { parseEsm } from './es-module-lexer';
/*
TODO: Add tests
Catches:
import a from 'b'
import 'b';
import('b');
export{a};
export default a;

Doesn't catch:
EXPORT{a}
exports.a = 1
module.exports = 1
*/
const esmPattern = /\b(?:import|export)\b/;

export const isESM = (code: string) => {
if (esmPattern.test(code)) {
const [imports, exports] = parseEsm(code);
return imports.length > 0 || exports.length > 0;
}
return false;
};
61 changes: 40 additions & 21 deletions src/utils/transform/transform-dynamic-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,33 @@ import MagicString from 'magic-string';
import type { RawSourceMap } from '../../source-map';
import { parseEsm } from '../es-module-lexer';

const checkEsModule = `.then((mod)=>{
const exports = Object.keys(mod);
if(
exports.length===1&&exports[0]==='default'&&mod.default&&mod.default.__esModule
){
return mod.default
const handlerName = '___tsxInteropDynamicImport';
const handleEsModuleFunction = `function ${handlerName}${(function (imported: Record<string, unknown>) {
const d = 'default';
const exports = Object.keys(imported);
if (
exports.length === 1
&& exports[0] === d
&& imported[d]
&& typeof imported[d] === 'object'
&& '__esModule' in imported[d]
) {
return imported[d];
}
return mod
})`
// replaceAll is not supported in Node 12
// eslint-disable-next-line unicorn/prefer-string-replace-all
.replace(/[\n\t]+/g, '');

export function transformDynamicImport(
return imported;
}).toString().slice('function'.length)}`;

const handleDynamicImport = `.then(${handlerName})`;

const esmImportPattern = /\bimport\b/;

export const transformDynamicImport = (
filePath: string,
code: string,
) {
) => {
// Naive check
if (!code.includes('import')) {
if (!esmImportPattern.test(code)) {
return;
}

Expand All @@ -33,14 +41,25 @@ export function transformDynamicImport(
const magicString = new MagicString(code);

for (const dynamicImport of dynamicImports) {
magicString.appendRight(dynamicImport.se, checkEsModule);
magicString.appendRight(dynamicImport.se, handleDynamicImport);
}

magicString.append(handleEsModuleFunction);

const newCode = magicString.toString();
const newMap = magicString.generateMap({
source: filePath,
includeContent: false,

/**
* The performance hit on this is very high
* Since we're only transforming import()s, I think this may be overkill
*/
// hires: 'boundary',
}) as unknown as RawSourceMap;

return {
code: magicString.toString(),
map: magicString.generateMap({
source: filePath,
hires: true,
}) as unknown as RawSourceMap,
code: newCode,
map: newMap,
};
}
};
Loading