If you are having an issue with importing or referencing temp/config file in your react component in Storybook, this blog may be for you.
Introduction
If you are used to Sitecore Next.js, you'd be familiar with its generation of temp files (Fig 1) such as config.js or componentFactory.ts. These are files generated at build time to enable dynamic configuration of the app every time. They're meant to work OOTB in Next.js, but these become troublesome when we are no longer working in the Next.js environment such as jest (unit test) or Storybook.
Fig 1. An example of temp files.
We created a react component where we had to reference the temp config file (ex. import config from 'temp/config';
). Everything worked perfectly until we tried to build a story using that component. Then I was hit with this error:
WARN Force closed manager build
ModuleNotFoundError: Module not found: Error: Can't resolve 'temp/config' in 'C:\Project\src\rendering\nuscale\src\components\Feature\Navigation\Header'
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\Compilation.js:2016:28
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:798:13
at eval (eval at create (C:\Project\src\rendering\nuscale\node_modules\webpack\node_modules\tapable\lib\HookCodeFactory.js:33:10), :10:1)
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:270:22
at eval (eval at create (C:\Project\src\rendering\nuscale\node_modules\webpack\node_modules\tapable\lib\HookCodeFactory.js:33:10), :9:1)
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:434:22
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:116:11
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:670:25
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:855:8
at C:\Project\src\rendering\nuscale\node_modules\webpack\lib\NormalModuleFactory.js:975:5
resolve 'temp/config' in 'C:\Project\src\rendering\nuscale\src\components\Feature\Navigation\Header'
Parsed request is a module
using description file: C:\Project\src\rendering\nuscale\package.json (relative path: ./src/components/Feature/Navigation/Header)
Field 'browser' doesn't contain a valid alias configuration
resolve as module
C:\Project\src\rendering\nuscale\src\components\Feature\Navigation\Header\node_modules doesn't exist or is not a directory
C:\Project\src\rendering\nuscale\src\components\Feature\Navigation\node_modules doesn't exist or is not a directory
C:\Project\src\rendering\nuscale\src\components\Feature\node_modules doesn't exist or is not a directory
C:\Project\src\rendering\nuscale\src\components\node_modules doesn't exist or is not a directory
C:\Project\src\rendering\nuscale\src\node_modules doesn't exist or is not a directory
looking for modules in C:\Project\src\rendering\nuscale\node_modules
existing directory C:\Project\src\rendering\nuscale\node_modules\temp
using description file: C:\Project\src\rendering\nuscale\node_modules\temp\package.json (relative path: .)
using description file: C:\Project\src\rendering\nuscale\node_modules\temp\package.json (relative path: ./config)
no extension
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config doesn't exist
.mjs
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.mjs doesn't exist
.js
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.js doesn't exist
.jsx
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.jsx doesn't exist
.ts
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.ts doesn't exist
.tsx
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.tsx doesn't exist
.json
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.json doesn't exist
.cjs
Field 'browser' doesn't contain a valid alias configuration
C:\Project\src\rendering\nuscale\node_modules\temp\config.cjs doesn't exist
as directory
C:\Project\src\rendering\nuscale\node_modules\temp\config doesn't exist
C:\Project\src\rendering\node_modules doesn't exist or is not a directory
C:\Project\src\node_modules doesn't exist or is not a directory
C:\Project\node_modules doesn't exist or is not a directory
C:\node_modules doesn't exist or is not a directory
It really did not like the temp file because it simply didn't exist during Storybook build. The obvious solution here is to create it during the Storybook build. Here is how:
Solution
1. Copy the content from your already generated config.js file. Mine looks like this:
/* eslint-disable */
// Do not edit this file, it is auto-generated at build time!
// See scripts/bootstrap.ts to modify the generation of this file.
const config = {};
config.sitecoreApiKey = process.env.SITECORE_API_KEY || "no-api-key-set",
config.sitecoreApiHost = process.env.SITECORE_API_HOST || "",
config.jssAppName = process.env.JSS_APP_NAME || "nuscale",
config.graphQLEndpointPath = process.env.GRAPH_QL_ENDPOINT_PATH || "/sitecore/api/graph/edge",
config.graphQLEndpoint = process.env.GRAPH_QL_ENDPOINT || `${config.sitecoreApiHost}${config.graphQLEndpointPath}`;
module.exports = config;
2. Create a mock-config.js file in your root with the content you copied from Step 1. I created it at the root of the project under a folder called __mocks__.
3. Let Storybook know where to find this mock config file. In your Storybook's main.js, add this line of code: config.resolve.alias['temp/config'] = require.resolve('../path/to/your/mock-config.js');
inside your webpack modifier (reference mine if you do not have this. It's called webpackFinal). Below is my main.js. The path may require some trial and error depending on where you put your mock-config.js.
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"@storybook/preset-scss",
{
name: '@storybook/addon-postcss',
options: {
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
},
],
staticDirs: ['../public', '../src/stories/assets'],
"framework": "@storybook/react",
"core": {
"builder": "@storybook/builder-webpack5"
},
webpackFinal: async (config, { configType }) => {
config.resolve.plugins = [new TsconfigPathsPlugin()];
config.resolve.alias['temp/config'] = require.resolve('../__mocks__/mock-config.js'); // ADD THIS LINE
return config;
}
}
Conclusion
We looked at how to create mock config file and let Storybook know where to find it. This approach can be applied to other independent environments such as jest.