Skip to content

Commit

Permalink
fix: Fix the importing of ESModule node_modules (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
EntraptaJ authored Mar 16, 2020
1 parent b77b739 commit 4d48170
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 59 deletions.
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.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
],
"dependencies": {},
"devDependencies": {
"@types/node": "^13.7.1",
"@types/node": "^13.9.1",
"prettier": "^1.19.1",
"typescript": "^3.7.5"
"typescript": "^3.8.3"
},
"peerDependencies": {
"typescript": "^3.7.5"
"typescript": ">=3.7"
},
"engines": {
"node": ">= 13.7"
Expand All @@ -25,7 +25,7 @@
"test": "echo \"Error: no test specified\" && exit 1",
"prebuild": "tsc -p ./bin/",
"build": "node --experimental-specifier-resolution=node ./out/build/build.js",
"pretry": "npm run build",
"pretry": "npm run build && cp ./test/extras/ReactPikaPKG.json ./test/node_modules/@pika/react/package.json",
"try": "node --loader ./out/dist/index.js --experimental-specifier-resolution=node ./test/",
"prepublishOnly": "npm run build"
},
Expand Down
4 changes: 2 additions & 2 deletions src/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ export function getTSConfig(modulePath: string): CompilerOptions {
target: ts.ScriptTarget.ESNext,
moduleResolution: ts.ModuleResolutionKind.NodeJs,
allowJs: true,
skipLibCheck: true
skipLibCheck: true,
};
} else {
const tsConfigFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile)
.config;

tsConfigCache = ts.convertCompilerOptionsFromJson(
tsConfigFile.compilerOptions,
pathDirname(tsConfigPath)
pathDirname(tsConfigPath),
).options;
}

Expand Down
39 changes: 25 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { createRequire } from 'module';
import { basename, dirname } from 'path';
import ts from 'typescript';
import { fileURLToPath, pathToFileURL, URL } from 'url';
import { fileURLToPath, pathToFileURL, URL, format } from 'url';
import { findFiles } from './findFiles';
import {
ResolveContext,
ResolveResponse,
Source,
TransformContext,
TransformResponse,
ModuleFormat,
} from './types';
import { getTSConfig } from './Utils';

Expand Down Expand Up @@ -93,30 +94,40 @@ export async function dynamicInstantiate(url: string) {
};
}

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

export async function getFormat(
url: string,
context: never,
defaultGetFormat: Function,
) {
let format = formatCache.get(url);
if (format) return { format };

// If it's a TypeScript extension then force `module` mode.
if (extensionsRegex.test(url)) {
return {
format: 'module',
};
}
if (extensionsRegex.test(url)) format = 'module';

/**
* 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')) {
return {
format: 'dynamic',
if (!format) {
const defaultResolve = defaultGetFormat(url, context, defaultGetFormat) as {
format: ModuleFormat;
};
format = defaultResolve.format;

/**
* 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';
}
}

formatCache.set(url, format);

// Let Node.js handle all other URLs.
return defaultGetFormat(url, context, defaultGetFormat);
return {
format,
};
}

export async function transformSource(
Expand Down
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// src/types.ts

export type ModuleFormat =
| 'builtin'
| 'commonjs'
| 'dynamic'
| 'json'
| 'module'
| 'wasm';

export type Source = string | Buffer;

export interface ResolveContext {
Expand Down
13 changes: 13 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# TS-ESNode Test

This is a test of all diferent TS-ESNode issues and features in an all in one application.

The main entrypoint has a main import which could start an endless loop of import processing if the core import loading code is broken.

The core function in the entrypoint includes some logging to ensure the process is being launched properly.

It also dynamiclly loads Lab2 to ensure dynamic loading of TypeScript ESModules is working. If this is broken it could be with the findFiles function or the dynamic loading within TS-ESNode or Node.JS itself.

It also imports an example SSR React rendering function [Server.tsx](./src/Server.tsx) to ensure that we can import and load TSX as well as testing the loading of ESModule's from `node_modules`, once imported we run the function and log the resulting html text to console.

The NPM ESModule React module I'm using in this test/example is [@pika/react](https://github.com/pikapkg/react) to support this running in Node.JS I'm copying a package.json that includes `"type": "module"` as part of the prerun npm script.
44 changes: 44 additions & 0 deletions test/extras/ReactPikaPKG.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"_from": "@pika/react",
"_id": "@pika/[email protected]",
"_inBundle": false,
"_integrity": "sha512-v33Ub2QxntNpDFRnkj3tCbT6jMb7Etu7LOMQO/YAulLRIDtDvJdMwuOVJDdPYUmDtWjfWOB5xSP7nl7k0BApbQ==",
"_location": "/@pika/react",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "@pika/react",
"name": "@pika/react",
"escapedName": "@pika%2freact",
"scope": "@pika",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": ["#USER", "/"],
"_resolved": "https://registry.npmjs.org/@pika/react/-/react-16.13.1.tgz",
"_shasum": "20e47997d2a2f1e5da39a8e28b75db2ec77d99c6",
"_spec": "@pika/react",
"_where": "/workspace/test",
"bugs": {
"url": "https://github.com/facebook/react/issues"
},
"bundleDependencies": false,
"type": "module",
"dependencies": {},
"deprecated": false,
"description": "An actively maintained ESM build of React, the JavaScript library for building user interfaces.",
"homepage": "https://reactjs.org/",
"keywords": ["react"],
"license": "MIT",
"main": "source.production.js",
"module": "source.production.js",
"name": "@pika/react",
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react.git",
"directory": "packages/react"
},
"version": "16.13.1"
}
55 changes: 30 additions & 25 deletions test/package-lock.json

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

10 changes: 5 additions & 5 deletions test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
"license": "ISC",
"devDependencies": {
"@types/fs-extra": "^8.0.1",
"@types/node": "^13.1.8",
"@types/react": "^16.9.17",
"@types/react-dom": "^16.9.4",
"@types/node": "^13.9.1",
"@types/react-dom": "^16.9.5",
"typescript": "^3.8.0-dev.20200118"
},
"dependencies": {
"@pika/react": "^16.13.1",
"fs-extra": "^8.1.0",
"graphql": "^14.5.8",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"type-graphql": "^0.17.6"
}
}
5 changes: 5 additions & 0 deletions test/src/@types/react.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module '@pika/react' {
import * as ReactTypes from '@pika/react/types/index';

export default ReactTypes;
}
9 changes: 9 additions & 0 deletions test/src/Server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// test/src/Server.tsx
import React from '@pika/react';
import { renderToStaticMarkup } from 'react-dom/server';

export async function renderUI(): Promise<string> {
const [{ CoreApp }] = await Promise.all([import('./helloWorld')]);

return renderToStaticMarkup(<CoreApp />);
}
2 changes: 1 addition & 1 deletion test/src/helloWorld.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React from '@pika/react';

export function CoreApp(): React.ReactElement {
return (
Expand Down
8 changes: 7 additions & 1 deletion test/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ async function startHelloWorld(): Promise<void> {

console.log(`Result of Lab #2: `, lab2Result);

console.log('Importing helloWorld.tsx');
console.log('Importing Server.tsx');

const [{ renderUI }] = await Promise.all<typeof import('./Server')>([
import('./Server'),
]);

console.log('Rendering UI', await renderUI());
}

startHelloWorld();
2 changes: 1 addition & 1 deletion test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
"allowSyntheticDefaultImports": true,
"outDir": "dist"
},
"include": ["src/**/*.ts"]
"include": ["src/**/*"]
}

0 comments on commit 4d48170

Please sign in to comment.