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

[BUG] Webpack bundles typescript package when ts-runtime-checks is used #39

Open
jirutka opened this issue Oct 24, 2023 · 6 comments
Open

Comments

@jirutka
Copy link

jirutka commented Oct 24, 2023

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]
@GoogleFeud
Copy link
Owner

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.

@jirutka
Copy link
Author

jirutka commented Oct 24, 2023

  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!

@jirutka
Copy link
Author

jirutka commented Oct 25, 2023

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.

@jirutka
Copy link
Author

jirutka commented Oct 25, 2023

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).

@jirutka
Copy link
Author

jirutka commented Oct 25, 2023

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

@danehansen
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants