diff --git a/README.md b/README.md index fbe7d8c..376b07a 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ The function should return the updated Rsbuild configuration. ## Troubleshooting -### Error caused by bundling unwanted modules +### Error caused by bundling unexpected files Because Rspack temporarily does not support the `webpackInclude` magic comment, non-story files may be bundled, which could lead to build failures. These files can be ignored using `rspack.IgnorePlugin`. @@ -157,8 +157,8 @@ export default { ### Features -- [ ] Support TS type check (fork-ts-checker-webpack-plugin) -- [ ] Support more frameworks +- [x] Support TS type check (fork-ts-checker-webpack-plugin) +- [ ] Support more frameworks (Preact / Svelte / vanilla html / Lit) ### Rspack support diff --git a/packages/builder-rsbuild/package.json b/packages/builder-rsbuild/package.json index 41cacdc..f3bddac 100644 --- a/packages/builder-rsbuild/package.json +++ b/packages/builder-rsbuild/package.json @@ -78,6 +78,7 @@ "css-loader": "^6.7.1", "es-module-lexer": "^1.5.0", "express": "^4.17.3", + "fork-ts-checker-webpack-plugin": "^8.0.0", "fs-extra": "^11.1.0", "magic-string": "^0.30.5", "path-browserify": "^1.0.1", diff --git a/packages/builder-rsbuild/src/preview/iframe-rsbuild.config.ts b/packages/builder-rsbuild/src/preview/iframe-rsbuild.config.ts index 2d456b2..d2f3368 100644 --- a/packages/builder-rsbuild/src/preview/iframe-rsbuild.config.ts +++ b/packages/builder-rsbuild/src/preview/iframe-rsbuild.config.ts @@ -1,4 +1,4 @@ -import { extname, dirname, join, resolve } from 'path' +import { dirname, join, resolve } from 'path' // @ts-expect-error (I removed this on purpose, because it's incorrect) import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin' import type { Options } from '@storybook/types' @@ -15,6 +15,7 @@ import { getVirtualModules } from './virtual-module-mapping' import { loadConfig, mergeRsbuildConfig } from '@rsbuild/core' import type { RsbuildConfig } from '@rsbuild/core' import { webpack as docsWebpack } from '@storybook/addon-docs/dist/preset' +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin' const getAbsolutePath = (input: I): I => dirname(require.resolve(join(input, 'package.json'))) as any @@ -56,7 +57,7 @@ export default async (options: Options): Promise => { configType, presets, previewUrl, - // typescriptOptions, + typescriptOptions, features, } = options @@ -100,12 +101,12 @@ export default async (options: Options): Promise => { }) // TODO: not inclined to support fork-ts-checker-webpack-plugin - // const builderOptions = await getBuilderOptions(options) - // const shouldCheckTs = - // typescriptOptions.check && !typescriptOptions.skipCompiler - // const tsCheckOptions = typescriptOptions.checkOptions || {} + const shouldCheckTs = + typescriptOptions.check && !typescriptOptions.skipCompiler + const tsCheckOptions = typescriptOptions.checkOptions || {} // TODO: Rspack doesn't support persistent cache yet + // const builderOptions = await getBuilderOptions(options) // const cacheConfig = builderOptions.fsCache // ? { cache: { type: 'filesystem' as const } } // : {} @@ -257,6 +258,9 @@ export default async (options: Options): Promise => { process: require.resolve('process/browser.js'), }), new CaseSensitivePathsPlugin(), + shouldCheckTs + ? new ForkTsCheckerWebpackPlugin(tsCheckOptions) + : null, ].filter(Boolean), ) diff --git a/packages/builder-rsbuild/src/types.ts b/packages/builder-rsbuild/src/types.ts index 9bb9178..1a8ce32 100644 --- a/packages/builder-rsbuild/src/types.ts +++ b/packages/builder-rsbuild/src/types.ts @@ -1,11 +1,26 @@ import type { RsbuildConfig } from '@rsbuild/core' -import type { Builder, Options } from '@storybook/types' +import type { + Builder, + Options, + TypescriptOptions as TypeScriptOptionsBase, +} from '@storybook/types' +import type ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin' // Storybook's Stats are optional Webpack related property type RsbuildStats = { toJson: () => any } +/** + * Options for TypeScript usage within Storybook. + */ +export interface TypescriptOptions extends TypeScriptOptionsBase { + /** + * Configures `fork-ts-checker-webpack-plugin` + */ + checkOptions?: ConstructorParameters[0] +} + export type RsbuildBuilder = Builder export type RsbuildFinal = ( diff --git a/packages/react-rsbuild/src/types.ts b/packages/react-rsbuild/src/types.ts index 2bff080..bbebaba 100644 --- a/packages/react-rsbuild/src/types.ts +++ b/packages/react-rsbuild/src/types.ts @@ -1,8 +1,12 @@ import type { StorybookConfigRsbuild, BuilderOptions, + TypescriptOptions as TypescriptOptionsBuilder, } from 'storybook-builder-rsbuild' -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types' +import type { + StorybookConfig as StorybookConfigBase, + TypescriptOptions as TypescriptOptionsBase, +} from '@storybook/types' import type { PluginOptions as ReactDocgenTypescriptOptions } from '@storybook/react-docgen-typescript-plugin' type FrameworkName = 'storybook-react-rsbuild' @@ -21,6 +25,22 @@ export type FrameworkOptions = { legacyRootApi?: boolean } +type TypescriptOptionsReact = { + /** + * Sets the type of Docgen when working with React and TypeScript + * + * @default `'react-docgen'` + */ + reactDocgen: 'react-docgen-typescript' | 'react-docgen' | false + /** + * Configures `react-docgen-typescript-plugin` + * + * @default + * @see https://github.com/storybookjs/storybook/blob/next/code/builders/builder-webpack5/src/config/defaults.js#L4-L6 + */ + reactDocgenTypescriptOptions: ReactDocgenTypescriptOptions +} + type StorybookConfigFramework = { framework: | FrameworkName @@ -36,22 +56,9 @@ type StorybookConfigFramework = { options: BuilderOptions } } -} - -type TypescriptOptions = StorybookConfigBase['typescript'] & { - /** - * Sets the type of Docgen when working with React and TypeScript - * - * @default `'react-docgen'` - */ - reactDocgen: 'react-docgen-typescript' | 'react-docgen' | false - /** - * Configures `react-docgen-typescript-plugin` - * - * @default - * @see https://github.com/storybookjs/storybook/blob/next/code/builders/builder-webpack5/src/config/defaults.js#L4-L6 - */ - reactDocgenTypescriptOptions: ReactDocgenTypescriptOptions + typescript?: Partial< + TypescriptOptionsBase & TypescriptOptionsBuilder & TypescriptOptionsReact + > } /** @@ -62,6 +69,4 @@ export type StorybookConfig = Omit< keyof StorybookConfigRsbuild | keyof StorybookConfigFramework > & StorybookConfigRsbuild & - StorybookConfigFramework & { - typescript?: Partial - } + StorybookConfigFramework diff --git a/packages/vue3-rsbuild/src/types.ts b/packages/vue3-rsbuild/src/types.ts index dd36b55..bacd06a 100644 --- a/packages/vue3-rsbuild/src/types.ts +++ b/packages/vue3-rsbuild/src/types.ts @@ -1,6 +1,10 @@ -import type { StorybookConfig as StorybookConfigBase } from '@storybook/types' +import type { + StorybookConfig as StorybookConfigBase, + TypescriptOptions as TypescriptOptionsBaseAndVue, +} from '@storybook/types' import type { StorybookConfigRsbuild, + TypescriptOptions as TypescriptOptionsBuilder, BuilderOptions, } from 'storybook-builder-rsbuild' @@ -26,7 +30,7 @@ type StorybookConfigFramework = { options: BuilderOptions } } - typescript?: StorybookConfigBase['typescript'] + typescript?: Partial } /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 181ab86..122b424 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,6 +83,9 @@ importers: express: specifier: ^4.17.3 version: 4.19.2 + fork-ts-checker-webpack-plugin: + specifier: ^8.0.0 + version: 8.0.0(typescript@5.4.5)(webpack@5.91.0) fs-extra: specifier: ^11.1.0 version: 11.2.0 @@ -4214,6 +4217,10 @@ packages: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} dev: true + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + dev: false + /@types/pretty-hrtime@1.0.3: resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} dev: true @@ -5412,6 +5419,11 @@ packages: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: false + /camelcase-keys@6.2.2: resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} engines: {node: '>=8'} @@ -5798,6 +5810,17 @@ packages: dev: false optional: true + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: false + /cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} dependencies: @@ -5992,6 +6015,11 @@ packages: which-typed-array: 1.1.15 dev: true + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: false + /default-browser-id@3.0.0: resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} engines: {node: '>=12'} @@ -6281,7 +6309,6 @@ packages: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 - dev: true /es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} @@ -6919,6 +6946,29 @@ packages: dev: false optional: true + /fork-ts-checker-webpack-plugin@8.0.0(typescript@5.4.5)(webpack@5.91.0): + resolution: {integrity: sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==} + engines: {node: '>=12.13.0', yarn: '>=1.0.0'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + dependencies: + '@babel/code-frame': 7.24.2 + chalk: 4.1.2 + chokidar: 3.6.0 + cosmiconfig: 7.1.0 + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.6.2 + tapable: 2.2.1 + typescript: 5.4.5 + webpack: 5.91.0(esbuild@0.20.2) + dev: false + /form-data@2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} @@ -6949,6 +6999,15 @@ packages: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} dev: true + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: false + /fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} @@ -6990,6 +7049,10 @@ packages: minipass: 3.3.6 dev: true + /fs-monkey@1.0.6: + resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==} + dev: false + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -7426,6 +7489,14 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: false + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -7494,7 +7565,6 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} @@ -8379,6 +8449,13 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + /memfs@3.5.3: + resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} + engines: {node: '>= 4.0.0'} + dependencies: + fs-monkey: 1.0.6 + dev: false + /memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} dependencies: @@ -8669,6 +8746,10 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + /node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + dev: false + /node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} @@ -8939,6 +9020,13 @@ packages: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} dev: true + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: false + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -8947,7 +9035,6 @@ packages: error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} @@ -9893,6 +9980,11 @@ packages: dev: false optional: true + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: false + /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} diff --git a/sandboxes/react-rsbuild/.storybook/main.ts b/sandboxes/react-rsbuild/.storybook/main.ts index ad47378..5b67f52 100644 --- a/sandboxes/react-rsbuild/.storybook/main.ts +++ b/sandboxes/react-rsbuild/.storybook/main.ts @@ -27,6 +27,7 @@ const config: StorybookConfig = { }, typescript: { reactDocgen: 'react-docgen', + check: true, }, }