Skip to content

Commit

Permalink
fix(Node 14.4+) Fix the module by breaking out dynamicInstantiate i…
Browse files Browse the repository at this point in the history
…nto getSource jim (#133)

* feat: Almost have Node 14.4+ working

* fix(default destructuring): I'm an idiot

* cleanup: Remove unused debugging
  • Loading branch information
EntraptaJ authored Sep 15, 2020
1 parent 898e97a commit 08e8b3a
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 18 deletions.
4 changes: 1 addition & 3 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ RUN apk add --no-cache git
# Add Sudo to allow occasional usage of root. I wish I could remove this but I can't seem to get the node_modules volume working correctly.
RUN apk add --no-cache sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/node \
&& chmod 0440 /etc/sudoers.d/node

CMD [ "tail", "-f", "/dev/null" ]
&& chmod 0440 /etc/sudoers.d/node
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

This is a Node.JS Loader hook for Node.JS 13.9 or newer that transpiles TypeScript files into JavaScript using the `getFormat`, `resolve`, and `transformSource` hooks.

For Node.JS `<= 14.4` use `npm install @k-foss/[email protected]`

For Node.jS `=> 14.5` use `npm install @k-foss/ts-esnode@latest`

## Usage

You should already have `"type": "module"` in your `package.json`
Expand Down Expand Up @@ -57,8 +61,6 @@ Follow these steps to open this project in a container:

#### TODO

- I would really like to remove the hack to support destructed imports of legacy node_modules, see [this comment](https://github.com/K-FOSS/TS-ESNode/issues/1#issuecomment-596750379) for more information.

- Worker Threads to avoid the TypeScript compiling affecting main thread.

- Performance improvements. (Better file/import finding.)
Expand Down
2 changes: 2 additions & 0 deletions Testing/Tests/Axios/src/Axios.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export class AxiosSuite extends TestSuite {
public async test(): Promise<void> {
const axios = await getAxios();

console.log(axios);

notDeepStrictEqual(axios, {}, 'axios !== {}');

const dynamicAxios = await getAxiosDynamic();
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@k-foss/ts-estests": "^1.0.6",
"@semantic-release/changelog": "5.0.1",
"@semantic-release/git": "9.0.0",
"@types/node": "14.0.13",
"@types/node": "^14.10.1",
"@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0",
"conventional-changelog-conventionalcommits": "^4.3.0",
Expand All @@ -28,13 +28,13 @@
"eslint-plugin-standard": "^4.0.1",
"prettier": "2.0.5",
"semantic-release": "17.0.8",
"typescript": "3.9.5"
"typescript": "^4.0.2"
},
"peerDependencies": {
"typescript": ">=3.7"
},
"engines": {
"node": ">= 13.9"
"node": ">= 14.5"
},
"scripts": {
"pretest": "npm run build",
Expand Down
88 changes: 84 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { findFiles } from './findFiles';
import {
DynamicInstantiateResponse,
GetFormatResponse,
GetSourceContext,
GetSourceHook,
GetSourceResponse,
ModuleFormat,
ResolveContext,
ResolveResponse,
Expand Down Expand Up @@ -84,7 +87,6 @@ export async function resolve(
};
}

// Let Node.js handle all other specifiers.
return defaultResolve(specifier, { ...context, parentURL }, defaultResolve);
}

Expand Down Expand Up @@ -132,6 +134,8 @@ export async function dynamicInstantiate(

const formatCache = new Map<string, ModuleFormat>();

const CommonJSMap = new Set<string>();

export async function getFormat(
url: string,
context: never,
Expand All @@ -156,19 +160,95 @@ export async function getFormat(
* We need to use our dynamic hook on Node.JS CommonJS `node_modules` due to
* anything exported by TypeScript not being accepted by the exports check in Node
*/
if (url.includes('node_modules') && format === 'commonjs') {
format = 'dynamic';
}
// if (url.includes('node_modules') && format === 'commonjs') {
// format = 'dynamic';
// }
}

formatCache.set(url, format);

if (format === 'commonjs') {
format = 'module';

CommonJSMap.add(url);
}

// Let Node.js handle all other URLs.
return {
format,
};
}

export async function getSource(
url: string,
context: GetSourceContext,
defaultGetSource: GetSourceHook,
): Promise<GetSourceResponse> {
const { format } = context;

if (CommonJSMap.has(url)) {
const urlParts = url.split('/node_modules/');

// Extract the module name after node_modules.
const moduleName = urlParts.pop()!;

// With NPM, this is just top-level node_modules.
// With PNPM, this is the innermost node_modules.
const nodeModulesPath = urlParts.join('/node_modules/');

// Create a require function next to node_module, and import the CommonJS module.
const require = createRequire(`${nodeModulesPath}/noop.js`);
const dynModule = require(moduleName);
let isDefault = false;

let defaultKeys: string[] = [];

if (dynModule.default) {
if (dynModule.default !== dynModule) {
isDefault = true;
defaultKeys = Object.keys(dynModule.default);
}
}

// Export as ES Module.
const linkKeys = Object.keys(dynModule).filter((key) => key !== 'default');

const code = `
import {createRequire} from 'module';
const require = createRequire('${nodeModulesPath}/noop.js');
const cjs = require('${moduleName}');
${linkKeys
.map((prop: any) => `let $${prop} = cjs[${JSON.stringify(prop)}];`)
.join(';\n')}
${defaultKeys
.map(
(prop: any) =>
`let $default${prop} = cjs.default[${JSON.stringify(prop)}];`,
)
.join(';\n')}
export {
${linkKeys.map((prop: string) => ` $${prop} as ${prop},`).join('\n')}
}
export {
${defaultKeys.map((prop: string) => ` $default${prop} as ${prop},`).join('\n')}
}
${isDefault ? `export default cjs['default'];` : 'export default cjs;'}
`;

return {
source: code,
};
}

return defaultGetSource(url, context, defaultGetSource);
}

export async function transformSource(
source: Source,
context: TransformContext,
Expand Down
14 changes: 14 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,17 @@ export interface DynamicInstantiateResponse {
export interface GetFormatResponse {
format: ModuleFormat;
}

export interface GetSourceContext {
format: string;
}

export type GetSourceHook = (
url: string,
context: GetSourceContext,
defaultGetSource: GetSourceHook,
) => Promise<GetSourceResponse>;

export interface GetSourceResponse {
source: string | SharedArrayBuffer | Uint8Array;
}

0 comments on commit 08e8b3a

Please sign in to comment.