Skip to content

Commit

Permalink
Add the ability to run TypeScript files from CLI
Browse files Browse the repository at this point in the history
This allows `ts-node` to be used to run TypeScript files without having to compile them with `tsc` first. It also adds the necessary configs, including `tsconfig-paths` for `paths` import-alias resolution. Unfortunately, this means we have to remove the `--experimental-module-resolution=node` since `ts-node` uses its own loader and thus form of resolving modules.

See:

Setup
* https://medium.com/@jimcraft123hd/setting-up-path-alias-in-typescript-and-tsc-build-without-error-9f1dbc0bccd2

Issues with `ts-node`, ESM, and aliases
* TypeStrong/ts-node#1007
    - TypeStrong/ts-node#476
    - dividab/tsconfig-paths#122 (comment)
    - TypeStrong/ts-node#1450 (comment)
* TypeStrong/ts-node#1414
* TypeStrong/ts-node#995
    - TypeStrong/ts-node#639

Node issues with ESM
* https://nodejs.org/api/packages.html#determining-module-system
* nodejs/node#37468
  • Loading branch information
D-Pow committed Jan 12, 2022
1 parent 4593a5a commit 9d300e5
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 83 deletions.
48 changes: 43 additions & 5 deletions .npmrc
Expand Up @@ -51,11 +51,49 @@ engine-strict=true
# Options only include those that are valid `NODE_OPTIONS`.
# See: https://nodejs.org/api/cli.html#cli_node_options_options
#
# Allow top-level `await` calls so that webpack.config.mjs can await CJS imports.
# Allow JSON files to be imported in .mjs files.
# Allow automatic extension resolution as well as importing index.js from directories like source code can (e.g. `import file from './file'` instead of './file.js', and `import Utils from './utils'` instead of './utils/index.js').
# Allow the use of `import.meta.resolve` to use file paths to generate import-safe URLs (different from browser-safe URLs).
node-options='--experimental-top-level-await --experimental-json-modules --experimental-specifier-resolution=node --experimental-import-meta-resolve'
# Notable ones include:
#
# * --experimental-top-level-await
# Allow top-level `await` calls so that webpack.config.mjs can await CJS imports.
#
#
# * --experimental-json-modules
# Allow JSON files to be imported in .mjs files.
#
#
# * --experimental-import-meta-resolve
# Allow the use of `import.meta.resolve` to use file paths to generate import-safe URLs (different from browser-safe URLs).
#
#
# * --experimental-specifier-resolution=node
# Allow automatic extension resolution as well as importing index.js from directories like source code can
# e.g. `import file from './file'` instead of './file.js', and `import Utils from './utils'` instead of './utils/index.js'.
# Note: This will cause some `npx` commands to fail if the executables don't have a file extension on them (e.g. `npx tsc`).
# Relatedly, if using a different script runner/node module loader, e.g. `ts-node` to run TypeScript files, then they will
# sometimes fail as well b/c they'll either be shell scripts, will need their custom module loader (which won't work b/c we
# overrode it with this flag), or their loaders depending on files being translated to CommonJS before being executed (likely in RAM
# by their custom loader and/or NodeJS itself).
# This can be fixed in your own code by making it executable and adding a shebang, e.g.
# #!/usr/bin/env -S node
# #!/usr/bin/env -S npx
# #!/usr/bin/env -S npx ts-node
# For example, to use `ts-node` (for running TypeScript files from the CLI without having to compile them into JavaScript first),
# then they recommend running via either:
# 1. Using ts-node directly: `ts-node file.ts`
# 2. Using normal node command: ESM: `node --loader ts-node/esm file.ts` - CJS: `node -r ts-node/register file.ts`
# 3. Just run the file directly: Use a shebang like above (See: https://github.com/TypeStrong/ts-node/issues/639)
# 4. Add `--loader ts-node/(register|esm)` to `node-options` here (forces all node commands to run with `ts-node`, even `npx`)
# n. TL;DR - Check out this issue for a full analysis of way to run `ts-node`: https://github.com/TypeStrong/ts-node/issues/995
# But since `ts-node` uses its own module loader, we cannot set `--experimental-specifier-resolution=node` in `node-options`
# b/c it requires its own loader.
# Finally, for `ts-node`, if package.json uses `type: module`, then `ts-node` must use `module: ESNext` as well.
#
#
# * --no-warnings / --redirect-warnings=<file>
# Removes warnings from STDERR or redirects them to <file>.
# If you want to use ts-node by default for all files, then this will be necessary to reduce console noise:
# --loader=ts-node/register --no-warnings
node-options='--experimental-top-level-await --experimental-json-modules --experimental-import-meta-resolve'


# For some reason, `npm run` doesn't use the default shell,
Expand Down
2 changes: 1 addition & 1 deletion config/jest/jest.config.mjs
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs';

import { defaults } from 'jest-config';

import { Paths, FileTypeRegexes, ImportAliases } from '../utils';
import { Paths, FileTypeRegexes, ImportAliases } from '../utils/index.js';

/*
* Note: Add the `--no-cache` CLI option during development of jest transformers
Expand Down
2 changes: 1 addition & 1 deletion config/jest/jestAssetTransformer.mjs
Expand Up @@ -2,7 +2,7 @@ import path from 'path';

import JestCssModulesTransformer from 'jest-css-modules-transform';

import { FileTypeRegexes } from '../utils';
import { FileTypeRegexes } from '../utils/index.js';


/** @type {import('@jest/core/node_modules/@jest/transform/build/types').SyncTransformer} */
Expand Down
2 changes: 1 addition & 1 deletion config/utils/ESM/index.mjs
@@ -1 +1 @@
export * from './Imports';
export * from './Imports.mjs';
8 changes: 4 additions & 4 deletions config/webpack.config.mjs
Expand Up @@ -5,17 +5,17 @@ import CopyWebpackPlugin from 'copy-webpack-plugin';
import TerserJSPlugin from 'terser-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import MockRequestsWebpackPlugin from 'mock-requests/bin/MockRequestsWebpackPlugin';
import MockRequestsWebpackPlugin from 'mock-requests/bin/MockRequestsWebpackPlugin.js';

import AlterFilePostBuildPlugin from './AlterFilePostBuildPlugin';
import AlterFilePostBuildPlugin from './AlterFilePostBuildPlugin.mjs';
import {
Paths,
FileTypeRegexes,
getOutputFileName,
ImportAliases,
LocalLanHostIpAddresses,
} from './utils';
import babelConfig from './babel.config';
} from './utils/index.js';
import babelConfig from './babel.config.js';

import packageJson from '../package.json';
import manifestJson from '../src/manifest.json';
Expand Down
90 changes: 20 additions & 70 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -109,6 +109,8 @@
"shelljs": "^0.8.4",
"terser-webpack-plugin": "^4.2.3",
"ts-loader": "^9.2.6",
"ts-node": "^10.4.0",
"tsconfig-paths": "^3.12.0",
"typescript": "^4.5.4",
"webpack": "^5.61.0",
"webpack-cli": "^4.9.1",
Expand Down

0 comments on commit 9d300e5

Please sign in to comment.