diff --git a/code/builders/builder-manager/package.json b/code/builders/builder-manager/package.json index 389dedc50730..528677690f64 100644 --- a/code/builders/builder-manager/package.json +++ b/code/builders/builder-manager/package.json @@ -49,14 +49,12 @@ "@storybook/manager": "workspace:*", "@storybook/node-logger": "workspace:*", "@types/ejs": "^3.1.1", - "@types/find-cache-dir": "^3.2.1", "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", "browser-assert": "^1.2.1", "ejs": "^3.1.8", "esbuild": "^0.18.0", "esbuild-plugin-alias": "^0.2.1", "express": "^4.17.3", - "find-cache-dir": "^3.0.0", "fs-extra": "^11.1.0", "process": "^0.11.10", "util": "^0.12.4" diff --git a/code/builders/builder-manager/src/index.ts b/code/builders/builder-manager/src/index.ts index 89b9846184e6..b7923a64a2ba 100644 --- a/code/builders/builder-manager/src/index.ts +++ b/code/builders/builder-manager/src/index.ts @@ -40,10 +40,8 @@ export const getConfig: ManagerBuilder['getConfig'] = async (options) => { ? [...addonsEntryPoints, customManagerEntryPoint] : addonsEntryPoints; - const realEntryPoints = await wrapManagerEntries(entryPoints); - return { - entryPoints: realEntryPoints, + entryPoints: await wrapManagerEntries(entryPoints, options.cacheKey), outdir: join(options.outputDir || './', 'sb-addons'), format: 'iife', write: false, diff --git a/code/builders/builder-manager/src/utils/managerEntries.ts b/code/builders/builder-manager/src/utils/managerEntries.ts index 51413bfb852e..c30357851dd6 100644 --- a/code/builders/builder-manager/src/utils/managerEntries.ts +++ b/code/builders/builder-manager/src/utils/managerEntries.ts @@ -1,5 +1,5 @@ -import findCacheDirectory from 'find-cache-dir'; import fs from 'fs-extra'; +import { resolvePathInStorybookCache } from '@storybook/core-common'; import { join, parse, relative, sep } from 'node:path'; import slash from 'slash'; @@ -34,11 +34,11 @@ const sanitizeFinal = (path: string) => { * * We need to wrap each managerEntry with a try-catch because if we do not, a failing managerEntry can stop execution of other managerEntries. */ -export async function wrapManagerEntries(entrypoints: string[]) { +export async function wrapManagerEntries(entrypoints: string[], uniqueId?: string) { return Promise.all( entrypoints.map(async (entry, i) => { const { name, dir } = parse(entry); - const cacheLocation = findCacheDirectory({ name: 'sb-manager' }); + const cacheLocation = resolvePathInStorybookCache('sb-manager', uniqueId); if (!cacheLocation) { throw new Error('Could not create/find cache directory'); diff --git a/code/builders/builder-vite/src/vite-config.ts b/code/builders/builder-vite/src/vite-config.ts index b4d1744d3833..f4f258902b2b 100644 --- a/code/builders/builder-vite/src/vite-config.ts +++ b/code/builders/builder-vite/src/vite-config.ts @@ -1,5 +1,4 @@ import * as path from 'path'; -import findCacheDirectory from 'find-cache-dir'; import type { ConfigEnv, InlineConfig as ViteInlineConfig, @@ -7,7 +6,12 @@ import type { UserConfig as ViteConfig, InlineConfig, } from 'vite'; -import { isPreservingSymlinks, getFrameworkName, getBuilderOptions } from '@storybook/core-common'; +import { + isPreservingSymlinks, + getFrameworkName, + getBuilderOptions, + resolvePathInStorybookCache, +} from '@storybook/core-common'; import { globalsNameReferenceMap } from '@storybook/preview/globals'; import type { Options } from '@storybook/types'; import { @@ -54,7 +58,7 @@ export async function commonConfig( const sbConfig: InlineConfig = { configFile: false, - cacheDir: findCacheDirectory({ name: 'sb-vite' }), + cacheDir: resolvePathInStorybookCache('sb-vite', options.cacheKey), root: projectRoot, // Allow storybook deployed as subfolder. See https://github.com/storybookjs/builder-vite/issues/238 base: './', diff --git a/code/lib/core-common/src/utils/resolve-path-in-sb-cache.ts b/code/lib/core-common/src/utils/resolve-path-in-sb-cache.ts index de88c2e2c00b..af7135817aff 100644 --- a/code/lib/core-common/src/utils/resolve-path-in-sb-cache.ts +++ b/code/lib/core-common/src/utils/resolve-path-in-sb-cache.ts @@ -9,9 +9,9 @@ import findCacheDirectory from 'find-cache-dir'; * @param fileOrDirectoryName {string} Name of the file or directory * @return {string} Absolute path to the file or directory */ -export function resolvePathInStorybookCache(fileOrDirectoryName: string): string { +export function resolvePathInStorybookCache(fileOrDirectoryName: string, sub = 'default'): string { let cacheDirectory = findCacheDirectory({ name: 'storybook' }); - cacheDirectory ||= path.join(process.cwd(), '.cache/storybook'); + cacheDirectory ||= path.join(process.cwd(), '.cache', 'storybook'); - return path.join(cacheDirectory, fileOrDirectoryName); + return path.join(cacheDirectory, sub, fileOrDirectoryName); } diff --git a/code/lib/core-server/src/build-dev.ts b/code/lib/core-server/src/build-dev.ts index 4995785b8951..88c3ab483f06 100644 --- a/code/lib/core-server/src/build-dev.ts +++ b/code/lib/core-server/src/build-dev.ts @@ -1,5 +1,6 @@ import type { BuilderOptions, CLIOptions, LoadOptions, Options } from '@storybook/types'; import { + getProjectRoot, loadAllPresets, loadMainConfig, resolveAddonName, @@ -10,9 +11,9 @@ import { import prompts from 'prompts'; import invariant from 'tiny-invariant'; import { global } from '@storybook/global'; -import { telemetry } from '@storybook/telemetry'; +import { telemetry, oneWayHash } from '@storybook/telemetry'; -import { join, resolve } from 'path'; +import { join, relative, resolve } from 'path'; import { deprecate } from '@storybook/node-logger'; import dedent from 'ts-dedent'; import { readFile } from 'fs-extra'; @@ -49,17 +50,28 @@ export async function buildDevStandalone( name: 'shouldChangePort', message: `Port ${options.port} is not available. Would you like to run Storybook on port ${port} instead?`, }); - if (!shouldChangePort) process.exit(1); + if (!shouldChangePort) { + process.exit(1); + } + } + + const rootDir = getProjectRoot(); + const configDir = resolve(options.configDir); + const cacheKey = oneWayHash(relative(rootDir, configDir)); + + const cacheOutputDir = resolvePathInStorybookCache('public', cacheKey); + let outputDir = resolve(options.outputDir || cacheOutputDir); + if (options.smokeTest) { + outputDir = cacheOutputDir; } /* eslint-disable no-param-reassign */ options.port = port; options.versionCheck = versionCheck; options.configType = 'DEVELOPMENT'; - options.configDir = resolve(options.configDir); - options.outputDir = options.smokeTest - ? resolvePathInStorybookCache('public') - : resolve(options.outputDir || resolvePathInStorybookCache('public')); + options.configDir = configDir; + options.cacheKey = cacheKey; + options.outputDir = outputDir; options.serverChannelUrl = getServerChannelUrl(port, options); /* eslint-enable no-param-reassign */ diff --git a/code/lib/core-server/src/build-static.ts b/code/lib/core-server/src/build-static.ts index 01e79c6b6228..683da79eb0f1 100644 --- a/code/lib/core-server/src/build-static.ts +++ b/code/lib/core-server/src/build-static.ts @@ -1,6 +1,6 @@ import chalk from 'chalk'; import { copy, emptyDir, ensureDir } from 'fs-extra'; -import { dirname, isAbsolute, join, resolve } from 'path'; +import { dirname, join, relative, resolve } from 'path'; import { global } from '@storybook/global'; import { deprecate, logger } from '@storybook/node-logger'; import { getPrecedingUpgrade, telemetry } from '@storybook/telemetry'; @@ -35,13 +35,11 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption throw new Error("Won't remove current directory. Check your outputDir!"); } - options.outputDir = isAbsolute(options.outputDir) - ? options.outputDir - : join(process.cwd(), options.outputDir); + options.outputDir = resolve(options.outputDir); options.configDir = resolve(options.configDir); /* eslint-enable no-param-reassign */ - logger.info(chalk`=> Cleaning outputDir: {cyan ${options.outputDir.replace(process.cwd(), '')}}`); + logger.info(chalk`=> Cleaning outputDir: {cyan ${relative(process.cwd(), options.outputDir)}}`); if (options.outputDir === '/') { throw new Error("Won't remove directory '/'. Check your outputDir!"); } diff --git a/code/lib/core-server/src/utils/copy-all-static-files.ts b/code/lib/core-server/src/utils/copy-all-static-files.ts index 44f7bf12d31f..5b0fb5227353 100644 --- a/code/lib/core-server/src/utils/copy-all-static-files.ts +++ b/code/lib/core-server/src/utils/copy-all-static-files.ts @@ -1,6 +1,6 @@ import chalk from 'chalk'; import fs from 'fs-extra'; -import path from 'path'; +import { join, relative } from 'path'; import { logger } from '@storybook/node-logger'; import { getDirectoryFromWorkingDir } from '@storybook/core-common'; import { parseStaticDir } from './server-statics'; @@ -11,11 +11,19 @@ export async function copyAllStaticFiles(staticDirs: any[] | undefined, outputDi staticDirs.map(async (dir) => { try { const { staticDir, staticPath, targetDir } = await parseStaticDir(dir); - const targetPath = path.join(outputDir, targetDir); - logger.info(chalk`=> Copying static files: {cyan ${staticDir}} => {cyan ${targetDir}}`); + const targetPath = join(outputDir, targetDir); + + // we copy prebuild static files from node_modules/@storybook/manager & preview + if (!staticDir.includes('node_modules')) { + logger.info( + chalk`=> Copying static files: {cyan ${print(staticDir)}} => {cyan ${print( + targetDir + )}}` + ); + } // Storybook's own files should not be overwritten, so we skip such files if we find them - const skipPaths = ['index.html', 'iframe.html'].map((f) => path.join(targetPath, f)); + const skipPaths = ['index.html', 'iframe.html'].map((f) => join(targetPath, f)); await fs.copy(staticPath, targetPath, { dereference: true, preserveTimestamps: true, @@ -49,9 +57,13 @@ export async function copyAllStaticFilesRelativeToMain( }) ); - const targetPath = path.join(outputDir, to); - const skipPaths = ['index.html', 'iframe.html'].map((f) => path.join(targetPath, f)); - logger.info(chalk`=> Copying static files: {cyan ${from}} at {cyan ${targetPath}}`); + const targetPath = join(outputDir, to); + const skipPaths = ['index.html', 'iframe.html'].map((f) => join(targetPath, f)); + if (!from.includes('node_modules')) { + logger.info( + chalk`=> Copying static files: {cyan ${print(from)}} at {cyan ${print(targetPath)}}` + ); + } await fs.copy(from, targetPath, { dereference: true, preserveTimestamps: true, @@ -59,3 +71,6 @@ export async function copyAllStaticFilesRelativeToMain( }); }, Promise.resolve()); } +function print(p: string): string { + return relative(process.cwd(), p); +} diff --git a/code/lib/types/src/modules/core-common.ts b/code/lib/types/src/modules/core-common.ts index 53dcecdcc684..8f848909d8ed 100644 --- a/code/lib/types/src/modules/core-common.ts +++ b/code/lib/types/src/modules/core-common.ts @@ -157,6 +157,7 @@ export interface LoadOptions { packageJson: PackageJson; outputDir?: string; configDir?: string; + cacheKey?: string; ignorePreview?: boolean; extendServer?: (server: Server) => void; } diff --git a/code/yarn.lock b/code/yarn.lock index dfee4c87dc40..6fe3d551d312 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5136,14 +5136,12 @@ __metadata: "@storybook/manager": "workspace:*" "@storybook/node-logger": "workspace:*" "@types/ejs": "npm:^3.1.1" - "@types/find-cache-dir": "npm:^3.2.1" "@yarnpkg/esbuild-plugin-pnp": "npm:^3.0.0-rc.10" browser-assert: "npm:^1.2.1" ejs: "npm:^3.1.8" esbuild: "npm:^0.18.0" esbuild-plugin-alias: "npm:^0.2.1" express: "npm:^4.17.3" - find-cache-dir: "npm:^3.0.0" fs-extra: "npm:^11.1.0" process: "npm:^0.11.10" slash: "npm:^5.0.0" @@ -11204,9 +11202,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": - version: 1.0.30001566 - resolution: "caniuse-lite@npm:1.0.30001566" - checksum: cd163075b1a9feaf9c9f657c3551279fcdac471471d67ee57ab2286c7b5480168e6336e359741b469fa40e94716f0f95ec185d87bd57d58894d66d8c21d7db04 + version: 1.0.30001570 + resolution: "caniuse-lite@npm:1.0.30001570" + checksum: e47230d2016edea56e002fa462a5289f697b48dcfbf703fb01aecc6c98ad4ecaf945ab23c253cb7af056c2d05f266e4e4cbebf45132100e2c9367439cb95b95b languageName: node linkType: hard