ts-runtime-checks
ts-runtime-checks copied to clipboard
[BUG] Webpack bundles typescript package when ts-runtime-checks is used
Describe the bug
I’m using Webpack to bundle a TypeScript project into a single JS file that can be executed with Node.js. When I import and use the check
function from ts-runtime-checks
, I end up with a huge bundle that includes even typescript.js
.
Expected behavior Development dependencies should not be bundled.
Additional context
import { check } from 'ts-runtime-checks'
const [config, errors] = check<SomeType>(obj)
Relevant devDependencies:
- ts-loader: "^9.4.4",
- ts-patch: "^3.0.2",
- ts-runtime-checks: "^0.4.1",
- typescript: "^5.2.2",
- webpack: "^5.88.2",
- webpack-cli: "^5.1.4",
tsconfig.json:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment",
"moduleResolution": "node",
"target": "ES2022",
"module": "ES2022",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"paths": {
"react": ["./node_modules/preact/compat"],
"react-dom": ["./node_modules/preact/compat"]
},
"strictNullChecks": true,
"plugins": [
{
"transform": "ts-runtime-checks"
}
]
},
"include": ["src/**/*.ts", "src/**/*.tsx"]
}
webpack.config.mjs:
// @ts-check
import * as Path from 'node:path'
import webpack from 'webpack'
/** @type {import('webpack').Configuration} */
const cli = {
name: 'cli',
entry: './src/main.ts',
target: 'node',
plugins: [
// Don't split the output bundle into multiple files.
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
],
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
},
},
output: {
filename: 'cli.js',
path: Path.resolve('./dist'),
},
optimization: {
minimize: false,
},
}
export default [cli]
You could configure webpack to not bundle the library with the externals
option, I haven't tried it for myself but it should work. The value can be anything since the transformer won't leave any of the function calls in the code:
externals: {
"ts-runtime-checks": '...',
},
alternatively, you can declare the function yourself:
export declare function myCheckFn<T, _rawErrorData extends boolean = false, _M = { __$marker: "check" }>(prop: unknown) : [T, Array<_rawErrorData extends true ? ValidationError : string>];
so you end up importing only types from the library and therefore it doesn't get bundled.
externals: { "ts-runtime-checks": '...', },
~~I’ve already tried this, but it didn’t help.~~ EDIT: It does work, I must have made a mistake somewhere before. But it cannot be anything, but some valid value (e.g. true
) because it finds its way into the bundle (but would be removed by minimizer):
;// CONCATENATED MODULE: external "true"
const external_true_namespaceObject = true;
;// CONCATENATED MODULE: ./src/config.ts
alternatively, you can declare the function yourself:
This works!
I’m considering migrating to Rollup, which has a better tree-shaking algorithm. Tbh, I use Webpack in this project just because I inherited it.
Anyway, thanks for the quick answer and this awesome project!
I’m considering migrating to Rollup, which has a better tree-shaking algorithm.
Hm, I have the same problem with Rollup, so it’s not Webpack-specific.
I’m looking into your code, and now understand why it’s happening. It’s needed to clearly separate the build-time code (transformer) and runtime code (actually just type declarations).
A better workaround (but still just a mere workaround):
ts-runtime-checks.ts:
// Workaround for https://github.com/GoogleFeud/ts-runtime-checks/issues/39
import type {
check as checkFn,
createMatch as createMatchFn,
is as isFn,
} from 'ts-runtime-checks'
export type * from 'ts-runtime-checks'
export declare const check: typeof checkFn
export declare const createMatch: typeof createMatchFn
export declare const is: typeof isFn
whenever i attempt to use any of the lower cased methods from ts-runtime-checks
(check, is, as, etc...), my build breaks. i get errors of
WARNING in ../reponame/node_modules/typescript/lib/typescript.js 5288:14-36 Critical dependency: the request of a dependency is an expression
and ERROR in ../reponame/node_modules/ts-runtime-checks/dist/transformer.js 224:25-40 Module not found: Error: Can't resolve 'path' in '/Users/username/Documents/reponame/node_modules/ts-runtime-checks/dist'
any ideas what im doing wrong? thanks.