vite-plugin-storybook-nextjs 0.0.14 → 1.0.0--canary.9.b462d2b.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +97 -1
- package/dist/index.cjs +28 -2
- package/dist/index.js +27 -2
- package/dist/mocks/storybook.global.cjs +2 -1
- package/dist/mocks/storybook.global.js +2 -1
- package/dist/plugins/next-image/alias/next-image.d.cts +1 -1
- package/dist/plugins/next-image/alias/next-image.d.ts +1 -1
- package/dist/plugins/next-mocks/alias/dynamic/index.cjs +61 -0
- package/dist/plugins/next-mocks/alias/dynamic/index.d.cts +37 -0
- package/dist/plugins/next-mocks/alias/dynamic/index.d.ts +37 -0
- package/dist/plugins/next-mocks/alias/dynamic/index.js +51 -0
- package/dist/plugins/next-mocks/alias/headers/cookies.d.cts +1 -1
- package/dist/plugins/next-mocks/alias/headers/cookies.d.ts +1 -1
- package/dist/plugins/next-mocks/alias/navigation/index.d.cts +2 -2
- package/dist/plugins/next-mocks/alias/navigation/index.d.ts +2 -2
- package/dist/plugins/next-mocks/alias/router/index.d.cts +2 -2
- package/dist/plugins/next-mocks/alias/router/index.d.ts +2 -2
- package/package.json +4 -1
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2024 Storybook <https://github.com/storybookjs>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,3 +1,99 @@
|
|
|
1
1
|
# vite-plugin-storybook-nextjs
|
|
2
2
|
|
|
3
|
-
This is a Vite plugin that allows you to use Next.js features in Vite.
|
|
3
|
+
This is a Vite plugin that allows you to use Next.js features in Vite. It is the basis for `@storybook/nextjs-vite` and should be used when running portable stories in Vitest.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Next.js Integration**: Seamlessly integrate Next.js features into your Vite project.
|
|
8
|
+
- **Storybook Compatibility**: Acts as the foundation for `@storybook/nextjs-vite`, enabling you to use Storybook with Next.js in a Vite environment.
|
|
9
|
+
- **Portable Stories**: Ideal for running portable stories in Vitest, ensuring your components are tested in an environment that closely mirrors production.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
To install the plugin, use your package manager of choice:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install vite-plugin-storybook-nextjs
|
|
17
|
+
# or
|
|
18
|
+
yarn add vite-plugin-storybook-nextjs
|
|
19
|
+
# or
|
|
20
|
+
pnpm add vite-plugin-storybook-nextjs
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Setup Vitest
|
|
26
|
+
|
|
27
|
+
To use the plugin, you need to set up Vitest in your project. You can do this by following the instructions in the [Vitest documentation](https://vitest.dev/guide/)
|
|
28
|
+
|
|
29
|
+
### Add the plugin to your vitest configuration
|
|
30
|
+
|
|
31
|
+
Add the plugin to your Vitest configuration file. This ensures that Vitest is aware of the Next.js features provided by the plugin.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// vitest.config.ts
|
|
35
|
+
import { defineConfig } from "vite";
|
|
36
|
+
import nextjs from "vite-plugin-storybook-nextjs";
|
|
37
|
+
|
|
38
|
+
export default defineConfig({
|
|
39
|
+
plugins: [nextjs()],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Usage with portable stories
|
|
44
|
+
|
|
45
|
+
[Portable stories](https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest) are Storybook stories which can be used in external environments, such as Vitest.
|
|
46
|
+
|
|
47
|
+
This plugin is necessary to run portable stories in Vitest, as it provides the necessary Next.js features to ensure that your components are tested in an environment that closely mirrors production.
|
|
48
|
+
|
|
49
|
+
#### Experimental @storybook/experimental-vitest-plugin
|
|
50
|
+
|
|
51
|
+
The experimental `@storybook/experimental-vitest-plugin` can be used to automatically transform your stories at Vitest runtime to in-memory test files. This allows you to run your stories in a Vitest environment without needing to manually transform your stories. Please visit https://github.com/storybookjs/vitest-plugin for more information.
|
|
52
|
+
|
|
53
|
+
## Configuration Options
|
|
54
|
+
|
|
55
|
+
You can configure the plugin using the following options:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
type VitePluginOptions = {
|
|
59
|
+
/**
|
|
60
|
+
* Provide the path to your Next.js project directory
|
|
61
|
+
* @default process.cwd()
|
|
62
|
+
*/
|
|
63
|
+
dir?: string;
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Limitations and differences to the Webpack5-based integration of Next.js in Storybook
|
|
68
|
+
|
|
69
|
+
### next/font staticDir mapping obsolete
|
|
70
|
+
|
|
71
|
+
You don't need to map your custom font directory in Storybook's staticDir configuration. Vite will automatically serve the files in the public directory and provide assets during production build.
|
|
72
|
+
|
|
73
|
+
### CSS/SASS
|
|
74
|
+
|
|
75
|
+
The `sassOptions` in `next.config.js` is not supported. Please use Vite's configuration options to configure the Sass compiler:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
css: {
|
|
79
|
+
preprocessorOptions: {
|
|
80
|
+
scss: {
|
|
81
|
+
quietDeps: true
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Next.js: Server Actions
|
|
88
|
+
|
|
89
|
+
When using components that rely on Next.js Server Actions, there are some limitations to be aware of. Specifically, you need to ensure that your story files are set up to use the jsdom environment in Vitest for the case that your default Virtual DOM environment is set to happy-dom. This can be done by adding a special comment at the top of your story files:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
// @vitest-environment jsdom
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
This comment ensures that the components using Next.js Server Actions are properly handled in a jsdom environment, which is necessary for them to function correctly in Vitest.
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
This project is licensed under the MIT License.
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var utils_js = require('next/dist/build/utils.js');
|
|
|
21
21
|
var options_js = require('next/dist/build/swc/options.js');
|
|
22
22
|
var loadConfig = require('next/dist/server/config.js');
|
|
23
23
|
var constants_js = require('next/dist/shared/lib/constants.js');
|
|
24
|
+
var MagicString = require('magic-string');
|
|
24
25
|
var os = require('os');
|
|
25
26
|
var querystring = require('querystring');
|
|
26
27
|
var imageSizeOf = require('image-size');
|
|
@@ -35,6 +36,7 @@ var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
|
35
36
|
var loaderUtils__default = /*#__PURE__*/_interopDefault(loaderUtils);
|
|
36
37
|
var loadJsConfig__default = /*#__PURE__*/_interopDefault(loadJsConfig);
|
|
37
38
|
var loadConfig__default = /*#__PURE__*/_interopDefault(loadConfig);
|
|
39
|
+
var MagicString__default = /*#__PURE__*/_interopDefault(MagicString);
|
|
38
40
|
var imageSizeOf__default = /*#__PURE__*/_interopDefault(imageSizeOf);
|
|
39
41
|
|
|
40
42
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -727,6 +729,28 @@ if (typeof Promise.withResolvers === "undefined") {
|
|
|
727
729
|
return { promise, resolve: resolve4, reject };
|
|
728
730
|
};
|
|
729
731
|
}
|
|
732
|
+
var vitePluginNextDynamic = () => ({
|
|
733
|
+
name: "vite-plugin-storybook-nextjs-dynamic",
|
|
734
|
+
transform(code, id) {
|
|
735
|
+
const dynamicImportRegex = /dynamic\(\s*async\s*\(\s*\)\s*=>\s*\{\s*typeof\s*require\.resolveWeak\s*!==\s*"undefined"\s*&&\s*require\.resolveWeak\(([^)]+)\);\s*\}/g;
|
|
736
|
+
if (dynamicImportRegex.test(code)) {
|
|
737
|
+
const s = new MagicString__default.default(code);
|
|
738
|
+
dynamicImportRegex.lastIndex = 0;
|
|
739
|
+
let match = dynamicImportRegex.exec(code);
|
|
740
|
+
while (match !== null) {
|
|
741
|
+
const [fullMatch, importPath] = match;
|
|
742
|
+
const newImport = `dynamic(() => import(${importPath})`;
|
|
743
|
+
s.overwrite(match.index, match.index + fullMatch.length, newImport);
|
|
744
|
+
match = dynamicImportRegex.exec(code);
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
code: s.toString(),
|
|
748
|
+
map: s.generateMap({ hires: true })
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
});
|
|
730
754
|
|
|
731
755
|
// src/utils.ts
|
|
732
756
|
var VITEST_PLUGIN_NAME = "vite-plugin-storybook-nextjs";
|
|
@@ -866,7 +890,8 @@ var getAlias2 = (env) => ({
|
|
|
866
890
|
"server-only": getEntryPoint2("server-only", env),
|
|
867
891
|
"@opentelemetry/api": require4.resolve(
|
|
868
892
|
"next/dist/compiled/@opentelemetry/api"
|
|
869
|
-
)
|
|
893
|
+
),
|
|
894
|
+
"next/dynamic": getEntryPoint2("dynamic", env)
|
|
870
895
|
});
|
|
871
896
|
var vitePluginNextMocks = () => ({
|
|
872
897
|
name: "vite-plugin-next-mocks",
|
|
@@ -937,7 +962,8 @@ function VitePlugin({ dir = process.cwd() } = {}) {
|
|
|
937
962
|
vitePluginNextSwc(dir, nextConfigResolver),
|
|
938
963
|
vitePluginNextEnv(dir, nextConfigResolver),
|
|
939
964
|
vitePluginNextImage(nextConfigResolver),
|
|
940
|
-
vitePluginNextMocks()
|
|
965
|
+
vitePluginNextMocks(),
|
|
966
|
+
vitePluginNextDynamic()
|
|
941
967
|
];
|
|
942
968
|
}
|
|
943
969
|
var src_default = VitePlugin;
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { getSupportedBrowsers } from 'next/dist/build/utils.js';
|
|
|
19
19
|
import { getParserOptions } from 'next/dist/build/swc/options.js';
|
|
20
20
|
import loadConfig from 'next/dist/server/config.js';
|
|
21
21
|
import { PHASE_DEVELOPMENT_SERVER, PHASE_TEST, PHASE_PRODUCTION_BUILD } from 'next/dist/shared/lib/constants.js';
|
|
22
|
+
import MagicString from 'magic-string';
|
|
22
23
|
import { cpus } from 'node:os';
|
|
23
24
|
import { decode } from 'node:querystring';
|
|
24
25
|
import imageSizeOf from 'image-size';
|
|
@@ -713,6 +714,28 @@ if (typeof Promise.withResolvers === "undefined") {
|
|
|
713
714
|
return { promise, resolve: resolve4, reject };
|
|
714
715
|
};
|
|
715
716
|
}
|
|
717
|
+
var vitePluginNextDynamic = () => ({
|
|
718
|
+
name: "vite-plugin-storybook-nextjs-dynamic",
|
|
719
|
+
transform(code, id) {
|
|
720
|
+
const dynamicImportRegex = /dynamic\(\s*async\s*\(\s*\)\s*=>\s*\{\s*typeof\s*require\.resolveWeak\s*!==\s*"undefined"\s*&&\s*require\.resolveWeak\(([^)]+)\);\s*\}/g;
|
|
721
|
+
if (dynamicImportRegex.test(code)) {
|
|
722
|
+
const s = new MagicString(code);
|
|
723
|
+
dynamicImportRegex.lastIndex = 0;
|
|
724
|
+
let match = dynamicImportRegex.exec(code);
|
|
725
|
+
while (match !== null) {
|
|
726
|
+
const [fullMatch, importPath] = match;
|
|
727
|
+
const newImport = `dynamic(() => import(${importPath})`;
|
|
728
|
+
s.overwrite(match.index, match.index + fullMatch.length, newImport);
|
|
729
|
+
match = dynamicImportRegex.exec(code);
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
code: s.toString(),
|
|
733
|
+
map: s.generateMap({ hires: true })
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
});
|
|
716
739
|
|
|
717
740
|
// src/utils.ts
|
|
718
741
|
var VITEST_PLUGIN_NAME = "vite-plugin-storybook-nextjs";
|
|
@@ -852,7 +875,8 @@ var getAlias2 = (env) => ({
|
|
|
852
875
|
"server-only": getEntryPoint2("server-only", env),
|
|
853
876
|
"@opentelemetry/api": require4.resolve(
|
|
854
877
|
"next/dist/compiled/@opentelemetry/api"
|
|
855
|
-
)
|
|
878
|
+
),
|
|
879
|
+
"next/dynamic": getEntryPoint2("dynamic", env)
|
|
856
880
|
});
|
|
857
881
|
var vitePluginNextMocks = () => ({
|
|
858
882
|
name: "vite-plugin-next-mocks",
|
|
@@ -923,7 +947,8 @@ function VitePlugin({ dir = process.cwd() } = {}) {
|
|
|
923
947
|
vitePluginNextSwc(dir, nextConfigResolver),
|
|
924
948
|
vitePluginNextEnv(dir, nextConfigResolver),
|
|
925
949
|
vitePluginNextImage(nextConfigResolver),
|
|
926
|
-
vitePluginNextMocks()
|
|
950
|
+
vitePluginNextMocks(),
|
|
951
|
+
vitePluginNextDynamic()
|
|
927
952
|
];
|
|
928
953
|
}
|
|
929
954
|
var src_default = VitePlugin;
|
|
@@ -43,7 +43,8 @@ var getAlias2 = (env) => ({
|
|
|
43
43
|
"server-only": getEntryPoint2("server-only", env),
|
|
44
44
|
"@opentelemetry/api": require2.resolve(
|
|
45
45
|
"next/dist/compiled/@opentelemetry/api"
|
|
46
|
-
)
|
|
46
|
+
),
|
|
47
|
+
"next/dynamic": getEntryPoint2("dynamic", env)
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
// src/mocks/storybook.global.ts
|
|
@@ -36,7 +36,8 @@ var getAlias2 = (env) => ({
|
|
|
36
36
|
"server-only": getEntryPoint2("server-only", env),
|
|
37
37
|
"@opentelemetry/api": require2.resolve(
|
|
38
38
|
"next/dist/compiled/@opentelemetry/api"
|
|
39
|
-
)
|
|
39
|
+
),
|
|
40
|
+
"next/dynamic": getEntryPoint2("dynamic", env)
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
// src/mocks/storybook.global.ts
|
|
@@ -2,7 +2,7 @@ import * as next_dist_shared_lib_get_img_props from 'next/dist/shared/lib/get-im
|
|
|
2
2
|
import * as _NextImage from 'next/image';
|
|
3
3
|
import React__default from 'next/dist/compiled/react';
|
|
4
4
|
|
|
5
|
-
declare const MockedNextImage: React__default.ForwardRefExoticComponent<Omit<React__default.DetailedHTMLProps<React__default.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "
|
|
5
|
+
declare const MockedNextImage: React__default.ForwardRefExoticComponent<Omit<React__default.DetailedHTMLProps<React__default.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "height" | "width" | "loading" | "ref" | "alt" | "src" | "srcSet"> & {
|
|
6
6
|
src: string | next_dist_shared_lib_get_img_props.StaticImport;
|
|
7
7
|
alt: string;
|
|
8
8
|
width?: number | `${number}` | undefined;
|
|
@@ -2,7 +2,7 @@ import * as next_dist_shared_lib_get_img_props from 'next/dist/shared/lib/get-im
|
|
|
2
2
|
import * as _NextImage from 'next/image';
|
|
3
3
|
import React__default from 'next/dist/compiled/react';
|
|
4
4
|
|
|
5
|
-
declare const MockedNextImage: React__default.ForwardRefExoticComponent<Omit<React__default.DetailedHTMLProps<React__default.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "
|
|
5
|
+
declare const MockedNextImage: React__default.ForwardRefExoticComponent<Omit<React__default.DetailedHTMLProps<React__default.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "height" | "width" | "loading" | "ref" | "alt" | "src" | "srcSet"> & {
|
|
6
6
|
src: string | next_dist_shared_lib_get_img_props.StaticImport;
|
|
7
7
|
alt: string;
|
|
8
8
|
width?: number | `${number}` | undefined;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var Loadable = require('next/dist/shared/lib/loadable.shared-runtime.js');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var Loadable__default = /*#__PURE__*/_interopDefault(Loadable);
|
|
11
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
12
|
+
|
|
13
|
+
// src/plugins/next-mocks/alias/dynamic/index.tsx
|
|
14
|
+
function convertModule(mod) {
|
|
15
|
+
return { default: mod?.default || mod };
|
|
16
|
+
}
|
|
17
|
+
function noSSR() {
|
|
18
|
+
throw new Error("noSSR is not implemented in Storybook");
|
|
19
|
+
}
|
|
20
|
+
function dynamic(dynamicOptions, options) {
|
|
21
|
+
const loadableFn = Loadable__default.default;
|
|
22
|
+
if (options?.ssr === false) {
|
|
23
|
+
delete options.ssr;
|
|
24
|
+
}
|
|
25
|
+
let loadableOptions = {
|
|
26
|
+
// A loading component is not required, so we default it
|
|
27
|
+
loading: ({ error, isLoading, pastDelay }) => {
|
|
28
|
+
if (!pastDelay) return null;
|
|
29
|
+
if (process.env.NODE_ENV !== "production") {
|
|
30
|
+
if (isLoading) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (error) {
|
|
34
|
+
return /* @__PURE__ */ React__default.default.createElement("p", null, error.message, /* @__PURE__ */ React__default.default.createElement("br", null), error.stack);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
if (dynamicOptions instanceof Promise) {
|
|
41
|
+
loadableOptions.loader = () => dynamicOptions;
|
|
42
|
+
} else if (typeof dynamicOptions === "function") {
|
|
43
|
+
loadableOptions.loader = dynamicOptions;
|
|
44
|
+
} else if (typeof dynamicOptions === "object") {
|
|
45
|
+
loadableOptions = { ...loadableOptions, ...dynamicOptions };
|
|
46
|
+
}
|
|
47
|
+
loadableOptions = { ...loadableOptions, ...options };
|
|
48
|
+
const loaderFn = loadableOptions.loader;
|
|
49
|
+
const loader = () => loaderFn != null ? loaderFn().then(convertModule) : Promise.resolve(convertModule(() => null));
|
|
50
|
+
if (loadableOptions.loadableGenerated) {
|
|
51
|
+
loadableOptions = {
|
|
52
|
+
...loadableOptions,
|
|
53
|
+
...loadableOptions.loadableGenerated
|
|
54
|
+
};
|
|
55
|
+
delete loadableOptions.loadableGenerated;
|
|
56
|
+
}
|
|
57
|
+
return loadableFn({ ...loadableOptions, loader });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.default = dynamic;
|
|
61
|
+
exports.noSSR = noSSR;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React__default, { JSX } from 'react';
|
|
2
|
+
|
|
3
|
+
type ComponentModule<P = Record<string, unknown>> = {
|
|
4
|
+
default: React__default.ComponentType<P>;
|
|
5
|
+
};
|
|
6
|
+
declare type LoaderComponent<P = Record<string, unknown>> = Promise<React__default.ComponentType<P> | ComponentModule<P>>;
|
|
7
|
+
declare type Loader<P = Record<string, unknown>> = (() => LoaderComponent<P>) | LoaderComponent<P>;
|
|
8
|
+
type LoaderMap = {
|
|
9
|
+
[module: string]: () => Loader<unknown>;
|
|
10
|
+
};
|
|
11
|
+
type LoadableGeneratedOptions = {
|
|
12
|
+
webpack?(): unknown;
|
|
13
|
+
modules?(): LoaderMap;
|
|
14
|
+
};
|
|
15
|
+
type DynamicOptionsLoadingProps = {
|
|
16
|
+
error?: Error | null;
|
|
17
|
+
isLoading?: boolean;
|
|
18
|
+
pastDelay?: boolean;
|
|
19
|
+
retry?: () => void;
|
|
20
|
+
timedOut?: boolean;
|
|
21
|
+
};
|
|
22
|
+
type DynamicOptions<P = Record<string, unknown>> = LoadableGeneratedOptions & {
|
|
23
|
+
loading?: (loadingProps: DynamicOptionsLoadingProps) => JSX.Element | null;
|
|
24
|
+
loader?: Loader<P> | LoaderMap;
|
|
25
|
+
loadableGenerated?: LoadableGeneratedOptions;
|
|
26
|
+
ssr?: boolean;
|
|
27
|
+
};
|
|
28
|
+
declare function noSSR<P = Record<string, unknown>>(): React__default.ComponentType<P>;
|
|
29
|
+
/**
|
|
30
|
+
* This function lets you dynamically import a component.
|
|
31
|
+
* It uses [React.lazy()](https://react.dev/reference/react/lazy) with [Suspense](https://react.dev/reference/react/Suspense) under the hood.
|
|
32
|
+
*
|
|
33
|
+
* Read more: [Next.js Docs: `next/dynamic`](https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#nextdynamic)
|
|
34
|
+
*/
|
|
35
|
+
declare function dynamic<P = Record<string, unknown>>(dynamicOptions: DynamicOptions<P> | Loader<P>, options?: DynamicOptions<P>): React__default.ComponentType<P>;
|
|
36
|
+
|
|
37
|
+
export { type LoaderComponent, dynamic as default, noSSR };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React__default, { JSX } from 'react';
|
|
2
|
+
|
|
3
|
+
type ComponentModule<P = Record<string, unknown>> = {
|
|
4
|
+
default: React__default.ComponentType<P>;
|
|
5
|
+
};
|
|
6
|
+
declare type LoaderComponent<P = Record<string, unknown>> = Promise<React__default.ComponentType<P> | ComponentModule<P>>;
|
|
7
|
+
declare type Loader<P = Record<string, unknown>> = (() => LoaderComponent<P>) | LoaderComponent<P>;
|
|
8
|
+
type LoaderMap = {
|
|
9
|
+
[module: string]: () => Loader<unknown>;
|
|
10
|
+
};
|
|
11
|
+
type LoadableGeneratedOptions = {
|
|
12
|
+
webpack?(): unknown;
|
|
13
|
+
modules?(): LoaderMap;
|
|
14
|
+
};
|
|
15
|
+
type DynamicOptionsLoadingProps = {
|
|
16
|
+
error?: Error | null;
|
|
17
|
+
isLoading?: boolean;
|
|
18
|
+
pastDelay?: boolean;
|
|
19
|
+
retry?: () => void;
|
|
20
|
+
timedOut?: boolean;
|
|
21
|
+
};
|
|
22
|
+
type DynamicOptions<P = Record<string, unknown>> = LoadableGeneratedOptions & {
|
|
23
|
+
loading?: (loadingProps: DynamicOptionsLoadingProps) => JSX.Element | null;
|
|
24
|
+
loader?: Loader<P> | LoaderMap;
|
|
25
|
+
loadableGenerated?: LoadableGeneratedOptions;
|
|
26
|
+
ssr?: boolean;
|
|
27
|
+
};
|
|
28
|
+
declare function noSSR<P = Record<string, unknown>>(): React__default.ComponentType<P>;
|
|
29
|
+
/**
|
|
30
|
+
* This function lets you dynamically import a component.
|
|
31
|
+
* It uses [React.lazy()](https://react.dev/reference/react/lazy) with [Suspense](https://react.dev/reference/react/Suspense) under the hood.
|
|
32
|
+
*
|
|
33
|
+
* Read more: [Next.js Docs: `next/dynamic`](https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#nextdynamic)
|
|
34
|
+
*/
|
|
35
|
+
declare function dynamic<P = Record<string, unknown>>(dynamicOptions: DynamicOptions<P> | Loader<P>, options?: DynamicOptions<P>): React__default.ComponentType<P>;
|
|
36
|
+
|
|
37
|
+
export { type LoaderComponent, dynamic as default, noSSR };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Loadable from 'next/dist/shared/lib/loadable.shared-runtime.js';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
// src/plugins/next-mocks/alias/dynamic/index.tsx
|
|
5
|
+
function convertModule(mod) {
|
|
6
|
+
return { default: mod?.default || mod };
|
|
7
|
+
}
|
|
8
|
+
function noSSR() {
|
|
9
|
+
throw new Error("noSSR is not implemented in Storybook");
|
|
10
|
+
}
|
|
11
|
+
function dynamic(dynamicOptions, options) {
|
|
12
|
+
const loadableFn = Loadable;
|
|
13
|
+
if (options?.ssr === false) {
|
|
14
|
+
delete options.ssr;
|
|
15
|
+
}
|
|
16
|
+
let loadableOptions = {
|
|
17
|
+
// A loading component is not required, so we default it
|
|
18
|
+
loading: ({ error, isLoading, pastDelay }) => {
|
|
19
|
+
if (!pastDelay) return null;
|
|
20
|
+
if (process.env.NODE_ENV !== "production") {
|
|
21
|
+
if (isLoading) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (error) {
|
|
25
|
+
return /* @__PURE__ */ React.createElement("p", null, error.message, /* @__PURE__ */ React.createElement("br", null), error.stack);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
if (dynamicOptions instanceof Promise) {
|
|
32
|
+
loadableOptions.loader = () => dynamicOptions;
|
|
33
|
+
} else if (typeof dynamicOptions === "function") {
|
|
34
|
+
loadableOptions.loader = dynamicOptions;
|
|
35
|
+
} else if (typeof dynamicOptions === "object") {
|
|
36
|
+
loadableOptions = { ...loadableOptions, ...dynamicOptions };
|
|
37
|
+
}
|
|
38
|
+
loadableOptions = { ...loadableOptions, ...options };
|
|
39
|
+
const loaderFn = loadableOptions.loader;
|
|
40
|
+
const loader = () => loaderFn != null ? loaderFn().then(convertModule) : Promise.resolve(convertModule(() => null));
|
|
41
|
+
if (loadableOptions.loadableGenerated) {
|
|
42
|
+
loadableOptions = {
|
|
43
|
+
...loadableOptions,
|
|
44
|
+
...loadableOptions.loadableGenerated
|
|
45
|
+
};
|
|
46
|
+
delete loadableOptions.loadableGenerated;
|
|
47
|
+
}
|
|
48
|
+
return loadableFn({ ...loadableOptions, loader });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { dynamic as default, noSSR };
|
|
@@ -4,7 +4,7 @@ import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies/index.j
|
|
|
4
4
|
|
|
5
5
|
declare class RequestCookiesMock extends RequestCookies {
|
|
6
6
|
get: vitest.Mock<[name: string] | [next_dist_compiled__edge_runtime_cookies.RequestCookie], next_dist_compiled__edge_runtime_cookies.RequestCookie | undefined>;
|
|
7
|
-
getAll: vitest.Mock<[next_dist_compiled__edge_runtime_cookies.RequestCookie] | [name: string]
|
|
7
|
+
getAll: vitest.Mock<[] | [next_dist_compiled__edge_runtime_cookies.RequestCookie] | [name: string], next_dist_compiled__edge_runtime_cookies.RequestCookie[]>;
|
|
8
8
|
has: vitest.Mock<[name: string], boolean>;
|
|
9
9
|
set: vitest.Mock<[key: string, value: string] | [options: next_dist_compiled__edge_runtime_cookies.RequestCookie], this>;
|
|
10
10
|
delete: vitest.Mock<[names: string | string[]], boolean | boolean[]>;
|
|
@@ -4,7 +4,7 @@ import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies/index.j
|
|
|
4
4
|
|
|
5
5
|
declare class RequestCookiesMock extends RequestCookies {
|
|
6
6
|
get: vitest.Mock<[name: string] | [next_dist_compiled__edge_runtime_cookies.RequestCookie], next_dist_compiled__edge_runtime_cookies.RequestCookie | undefined>;
|
|
7
|
-
getAll: vitest.Mock<[next_dist_compiled__edge_runtime_cookies.RequestCookie] | [name: string]
|
|
7
|
+
getAll: vitest.Mock<[] | [next_dist_compiled__edge_runtime_cookies.RequestCookie] | [name: string], next_dist_compiled__edge_runtime_cookies.RequestCookie[]>;
|
|
8
8
|
has: vitest.Mock<[name: string], boolean>;
|
|
9
9
|
set: vitest.Mock<[key: string, value: string] | [options: next_dist_compiled__edge_runtime_cookies.RequestCookie], this>;
|
|
10
10
|
delete: vitest.Mock<[names: string | string[]], boolean | boolean[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import * as next_dist_shared_lib_app_router_context_shared_runtime from 'next/dist/shared/lib/app-router-context.shared-runtime';
|
|
3
3
|
import { Mock } from '@storybook/test';
|
|
4
4
|
import * as actual from 'next/dist/client/components/navigation.js';
|
|
@@ -28,7 +28,7 @@ declare const usePathname: Mock<[], string>;
|
|
|
28
28
|
declare const useSelectedLayoutSegment: Mock<[parallelRouteKey?: string | undefined], string | null>;
|
|
29
29
|
declare const useSelectedLayoutSegments: Mock<[parallelRouteKey?: string | undefined], string[]>;
|
|
30
30
|
declare const useRouter: Mock<[], next_dist_shared_lib_app_router_context_shared_runtime.AppRouterInstance>;
|
|
31
|
-
declare const useServerInsertedHTML: Mock<[callback: () =>
|
|
31
|
+
declare const useServerInsertedHTML: Mock<[callback: () => React.ReactNode], void>;
|
|
32
32
|
declare const notFound: Mock<[], never>;
|
|
33
33
|
interface Params {
|
|
34
34
|
[key: string]: string | string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import * as next_dist_shared_lib_app_router_context_shared_runtime from 'next/dist/shared/lib/app-router-context.shared-runtime';
|
|
3
3
|
import { Mock } from '@storybook/test';
|
|
4
4
|
import * as actual from 'next/dist/client/components/navigation.js';
|
|
@@ -28,7 +28,7 @@ declare const usePathname: Mock<[], string>;
|
|
|
28
28
|
declare const useSelectedLayoutSegment: Mock<[parallelRouteKey?: string | undefined], string | null>;
|
|
29
29
|
declare const useSelectedLayoutSegments: Mock<[parallelRouteKey?: string | undefined], string[]>;
|
|
30
30
|
declare const useRouter: Mock<[], next_dist_shared_lib_app_router_context_shared_runtime.AppRouterInstance>;
|
|
31
|
-
declare const useServerInsertedHTML: Mock<[callback: () =>
|
|
31
|
+
declare const useServerInsertedHTML: Mock<[callback: () => React.ReactNode], void>;
|
|
32
32
|
declare const notFound: Mock<[], never>;
|
|
33
33
|
interface Params {
|
|
34
34
|
[key: string]: string | string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import * as next_dist_client_with_router from 'next/dist/client/with-router';
|
|
3
3
|
import * as next_types from 'next/types';
|
|
4
4
|
import { Mock } from '@storybook/test';
|
|
@@ -40,6 +40,6 @@ declare const getRouter: () => {
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
declare const useRouter: Mock<[], originalRouter.NextRouter>;
|
|
43
|
-
declare const withRouter: Mock<[ComposedComponent: next_types.NextComponentType<next_types.NextPageContext, any, next_dist_client_with_router.WithRouterProps>],
|
|
43
|
+
declare const withRouter: Mock<[ComposedComponent: next_types.NextComponentType<next_types.NextPageContext, any, next_dist_client_with_router.WithRouterProps>], React.ComponentType<next_dist_client_with_router.ExcludeRouterProps<next_dist_client_with_router.WithRouterProps>>>;
|
|
44
44
|
|
|
45
45
|
export { createRouter, getRouter, useRouter, withRouter };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import * as next_dist_client_with_router from 'next/dist/client/with-router';
|
|
3
3
|
import * as next_types from 'next/types';
|
|
4
4
|
import { Mock } from '@storybook/test';
|
|
@@ -40,6 +40,6 @@ declare const getRouter: () => {
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
declare const useRouter: Mock<[], originalRouter.NextRouter>;
|
|
43
|
-
declare const withRouter: Mock<[ComposedComponent: next_types.NextComponentType<next_types.NextPageContext, any, next_dist_client_with_router.WithRouterProps>],
|
|
43
|
+
declare const withRouter: Mock<[ComposedComponent: next_types.NextComponentType<next_types.NextPageContext, any, next_dist_client_with_router.WithRouterProps>], React.ComponentType<next_dist_client_with_router.ExcludeRouterProps<next_dist_client_with_router.WithRouterProps>>>;
|
|
44
44
|
|
|
45
45
|
export { createRouter, getRouter, useRouter, withRouter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-storybook-nextjs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "1.0.0--canary.9.b462d2b.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vite-plugin",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"./browser/mocks/headers": "./dist/plugins/next-mocks/alias/headers/index.js",
|
|
29
29
|
"./browser/mocks/router": "./dist/plugins/next-mocks/alias/router/index.js",
|
|
30
30
|
"./browser/mocks/server-only": "./dist/plugins/next-mocks/alias/rsc/server-only.js",
|
|
31
|
+
"./browser/mocks/dynamic": "./dist/plugins/next-mocks/alias/dynamic/index.js",
|
|
31
32
|
"./browser/mocks/image": "./dist/plugins/next-image/alias/next-image.js",
|
|
32
33
|
"./browser/mocks/legacy-image": "./dist/plugins/next-image/alias/next-legacy-image.js",
|
|
33
34
|
"./browser/mocks/image-default-loader": "./dist/plugins/next-image/alias/image-default-loader.js",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"./node/mocks/headers": "./dist/plugins/next-mocks/alias/headers/index.cjs",
|
|
38
39
|
"./node/mocks/router": "./dist/plugins/next-mocks/alias/router/index.cjs",
|
|
39
40
|
"./node/mocks/server-only": "./dist/plugins/next-mocks/alias/rsc/server-only.cjs",
|
|
41
|
+
"./node/mocks/dynamic": "./dist/plugins/next-mocks/alias/dynamic/index.cjs",
|
|
40
42
|
"./node/mocks/image": "./dist/plugins/next-image/alias/next-image.cjs",
|
|
41
43
|
"./node/mocks/legacy-image": "./dist/plugins/next-image/alias/next-legacy-image.cjs",
|
|
42
44
|
"./node/mocks/image-default-loader": "./dist/plugins/next-image/alias/image-default-loader.cjs",
|
|
@@ -77,6 +79,7 @@
|
|
|
77
79
|
"dependencies": {
|
|
78
80
|
"@next/env": "^14.2.5",
|
|
79
81
|
"image-size": "^1.1.1",
|
|
82
|
+
"magic-string": "^0.30.11",
|
|
80
83
|
"module-alias": "^2.2.3",
|
|
81
84
|
"ts-dedent": "^2.2.0"
|
|
82
85
|
},
|