From cbaf55102664b0f874f5ef7802041b57c662fbe6 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 2 Aug 2022 09:15:06 +1000 Subject: [PATCH 1/4] Rename `example` => `sandbox` --- .gitignore | 2 +- code/package.json | 2 +- scripts/{example.ts => sandbox.ts} | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) rename scripts/{example.ts => sandbox.ts} (90%) diff --git a/.gitignore b/.gitignore index 4ae2a283700c..c8a737015be9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ dist .cache junit.xml /repros +/sandbox # Yarn stuff /**/.yarn/* @@ -17,4 +18,3 @@ junit.xml !/**/.yarn/versions /**/.pnp.* /yarn.lock -./examples/ \ No newline at end of file diff --git a/code/package.json b/code/package.json index 77f8d397acf0..16f3a58eb50c 100644 --- a/code/package.json +++ b/code/package.json @@ -62,7 +62,6 @@ "clean:dist": "del **/dist", "coverage": "codecov", "danger": "danger", - "example": "ts-node ../scripts/example.ts", "generate-repros": "zx ../scripts/repros-generator/index.mjs", "github-release": "github-release-from-changelog", "linear-export": "ts-node --project=../scripts/tsconfig.json ../scripts/linear-export.ts", @@ -80,6 +79,7 @@ "publish:latest": "lerna publish --exact --concurrency 1 --force-publish", "publish:next": "npm run publish:latest -- --npm-tag=next", "run-chromatics": "node -r esm ../scripts/run-chromatics.js", + "sandbox": "ts-node ../scripts/sandbox.ts", "serve-storybooks": "http-server ./built-storybooks -p 8001", "smoketest-storybooks": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true node -r esm ../scripts/smoketest-storybooks.js", "start": "yarn workspace official-storybook storybook --no-manager-cache", diff --git a/scripts/example.ts b/scripts/sandbox.ts similarity index 90% rename from scripts/example.ts rename to scripts/sandbox.ts index 27f83b1d751b..2bb1732d8e4a 100644 --- a/scripts/example.ts +++ b/scripts/sandbox.ts @@ -12,11 +12,11 @@ import { babelParse } from '../code/lib/csf-tools/src/babelParse'; const frameworks = ['react', 'angular']; const addons = ['a11y', 'storysource']; -const examplesDir = path.resolve(__dirname, '../examples'); +const sandboxDir = path.resolve(__dirname, '../sandbox'); const codeDir = path.resolve(__dirname, '../code'); async function getOptions() { - return getOptionsOrPrompt('yarn example', { + return getOptionsOrPrompt('yarn sandbox', { framework: { description: 'Which framework would you like to use?', values: frameworks, @@ -32,14 +32,14 @@ async function getOptions() { promptType: (_, { framework }) => framework === 'react', }, create: { - description: 'Create the example from scratch (rather than degitting it)?', + description: 'Create the template from scratch (rather than degitting it)?', }, forceDelete: { - description: 'Always delete an existing example, even if it has the same configuration?', + description: 'Always delete an existing sandbox, even if it has the same configuration?', promptType: false, }, forceReuse: { - description: 'Always reuse an existing example, even if it has a different configuration?', + description: 'Always reuse an existing sandbox, even if it has a different configuration?', promptType: false, }, link: { @@ -47,14 +47,14 @@ async function getOptions() { inverse: true, }, start: { - description: 'Start the example Storybook?', + description: 'Start the Storybook?', inverse: true, }, build: { - description: 'Build the example Storybook?', + description: 'Build the Storybook?', }, watch: { - description: 'Start building used packages in watch mode as well as the example Storybook?', + description: 'Start building used packages in watch mode as well as the Storybook?', }, dryRun: { description: "Don't execute commands, just list them (dry run)?", @@ -65,7 +65,7 @@ async function getOptions() { const steps = { repro: { command: 'repro', - description: 'Bootstrapping example', + description: 'Bootstrapping Template', icon: '👷', hasArgument: true, options: { @@ -89,13 +89,13 @@ const steps = { }, build: { command: 'build', - description: 'Building example', + description: 'Building Storybook', icon: '🔨', options: {}, }, dev: { command: 'dev', - description: 'Starting example', + description: 'Starting Storybook', icon: '🖥 ', options: {}, }, @@ -145,7 +145,7 @@ async function main() { const optionValues = await getOptions(); const { framework, forceDelete, forceReuse, link, dryRun } = optionValues; - const cwd = path.join(examplesDir, framework as string); + const cwd = path.join(sandboxDir, framework as string); const exists = await pathExists(cwd); let shouldDelete = exists && !forceReuse; @@ -167,7 +167,7 @@ async function main() { await executeCLIStep(steps.repro, { argument: cwd, optionValues: { template: framework }, - cwd: examplesDir, + cwd: sandboxDir, dryRun, }); From 36a006ab03076af53ac82e8832a07ef31f1a08c1 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 2 Aug 2022 10:05:22 +1000 Subject: [PATCH 2/4] Use `repro-next` in the example script! --- scripts/sandbox.ts | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/scripts/sandbox.ts b/scripts/sandbox.ts index f3bba4dcc796..667b8cbf80c4 100644 --- a/scripts/sandbox.ts +++ b/scripts/sandbox.ts @@ -9,8 +9,10 @@ import { exec } from '../code/lib/cli/src/repro-generators/scripts'; import { getInterpretedFile } from '../code/lib/core-common'; import { ConfigFile, readConfig, writeConfig } from '../code/lib/csf-tools'; import { babelParse } from '../code/lib/csf-tools/src/babelParse'; +import TEMPLATES from '../code/lib/cli/src/repro-templates'; -const frameworks = ['react', 'angular']; +type Template = keyof typeof TEMPLATES; +const templates: Template[] = Object.keys(TEMPLATES) as any; const addons = ['a11y', 'storysource']; const defaultAddons = [ 'actions', @@ -28,14 +30,11 @@ const defaultAddons = [ const sandboxDir = path.resolve(__dirname, '../sandbox'); const codeDir = path.resolve(__dirname, '../code'); -// TODO -- how to encode this information -const renderersMap = { react: 'react', angular: 'angular' }; - async function getOptions() { return getOptionsOrPrompt('yarn sandbox', { - framework: { - description: 'Which framework would you like to use?', - values: frameworks, + template: { + description: 'Which template would you like to use?', + values: templates, required: true as const, }, addon: { @@ -80,13 +79,15 @@ async function getOptions() { const steps = { repro: { - command: 'repro', + command: 'repro-next', description: 'Bootstrapping Template', icon: '👷', hasArgument: true, options: { - template: { values: frameworks }, - e2e: {}, + // TODO allow string valued options without fixed values + output: { values: [] as string[] }, + // TODO allow default values for strings + branch: { values: ['next'] }, }, }, add: { @@ -190,8 +191,8 @@ async function addStories( async function main() { const optionValues = await getOptions(); - const { framework, forceDelete, forceReuse, link, dryRun } = optionValues; - const cwd = path.join(sandboxDir, framework); + const { template, forceDelete, forceReuse, link, dryRun } = optionValues; + const cwd = path.join(sandboxDir, template); const exists = await pathExists(cwd); let shouldDelete = exists && !forceReuse; @@ -211,20 +212,19 @@ async function main() { if (!exists || shouldDelete) { await executeCLIStep(steps.repro, { - argument: cwd, - optionValues: { template: framework }, + argument: template, + optionValues: { output: cwd, branch: 'next' }, cwd: sandboxDir, dryRun, }); const mainConfig = await readMainConfig({ cwd }); - // TODO -- can we get the options type to return something more specific - const renderer = renderersMap[framework as 'react' | 'angular']; + const templateConfig = TEMPLATES[template as Template]; const storiesPath = 'stories'; // This may differ in different projects // Link in the template/components/index.js from the renderer - const rendererPath = path.join('node_modules', '@storybook', renderer); + const rendererPath = path.join('node_modules', templateConfig.expected.renderer); await ensureSymlink( path.join(codeDir, rendererPath, 'template', 'components'), path.resolve(cwd, storiesPath, 'components') @@ -255,6 +255,10 @@ async function main() { await writeConfig(mainConfig); if (link) { + await exec('yarn set version berry', { cwd }, { dryRun }); + await exec('yarn config set enableGlobalCache true', { cwd }, { dryRun }); + await exec('yarn config set nodeLinker node-modules', { cwd }, { dryRun }); + await executeCLIStep(steps.link, { argument: cwd, cwd: codeDir, From 31b0fe7df90dc9698d89224b588626135c522315 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 2 Aug 2022 14:32:03 +1000 Subject: [PATCH 3/4] Small fixes --- scripts/sandbox.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/sandbox.ts b/scripts/sandbox.ts index 667b8cbf80c4..93afbea593c9 100644 --- a/scripts/sandbox.ts +++ b/scripts/sandbox.ts @@ -120,13 +120,20 @@ const steps = { const logger = console; -const addPackageScripts = async ({ +async function findFirstPath(paths: string[], { cwd }: { cwd: string }) { + for (const filePath of paths) { + if (await pathExists(path.join(cwd, filePath))) return filePath; + } + return null; +} + +async function addPackageScripts({ cwd, scripts, }: { cwd: string; scripts: Record; -}) => { +}) { logger.info(`🔢 Adding package resolutions:`); const packageJsonPath = path.join(cwd, 'package.json'); const packageJson = await readJSON(packageJsonPath); @@ -135,7 +142,7 @@ const addPackageScripts = async ({ ...scripts, }; await writeJSON(packageJsonPath, packageJson, { spaces: 2 }); -}; +} async function readMainConfig({ cwd }: { cwd: string }) { const configDir = path.join(cwd, '.storybook'); @@ -165,10 +172,7 @@ const webpackFinalCode = ` })`; // paths are of the form 'node_modules/@storybook/react' -async function addStories( - paths: string[], - { mainConfig, cwd }: { mainConfig: ConfigFile; cwd: string } -) { +async function addStories(paths: string[], { mainConfig }: { mainConfig: ConfigFile }) { const stories = mainConfig.getFieldValue(['stories']) as string[]; const extraStoryDirsAndExistence = await Promise.all( paths @@ -192,7 +196,7 @@ async function main() { const optionValues = await getOptions(); const { template, forceDelete, forceReuse, link, dryRun } = optionValues; - const cwd = path.join(sandboxDir, template); + const cwd = path.join(sandboxDir, template.replace('/', '-')); const exists = await pathExists(cwd); let shouldDelete = exists && !forceReuse; @@ -221,7 +225,7 @@ async function main() { const mainConfig = await readMainConfig({ cwd }); const templateConfig = TEMPLATES[template as Template]; - const storiesPath = 'stories'; // This may differ in different projects + const storiesPath = await findFirstPath([path.join('src', 'stories'), 'stories'], { cwd }); // Link in the template/components/index.js from the renderer const rendererPath = path.join('node_modules', templateConfig.expected.renderer); @@ -250,7 +254,7 @@ async function main() { for (const addon of [...defaultAddons, ...optionValues.addon]) { storiesToAdd.push(path.join('node_modules', '@storybook', `addon-${addon}`)); } - await addStories(storiesToAdd, { mainConfig, cwd }); + await addStories(storiesToAdd, { mainConfig }); await writeConfig(mainConfig); From bcc60c1538ac1a96021f81c5a4bc810fc53d0cde Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 2 Aug 2022 14:30:25 +1000 Subject: [PATCH 4/4] Remove duplicate output --- code/lib/cli/src/repro-generators/scripts.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/code/lib/cli/src/repro-generators/scripts.ts b/code/lib/cli/src/repro-generators/scripts.ts index 35ac70ad6454..1558be57817c 100644 --- a/code/lib/cli/src/repro-generators/scripts.ts +++ b/code/lib/cli/src/repro-generators/scripts.ts @@ -77,7 +77,6 @@ export const exec = async ( }); child.stderr.pipe(process.stderr); - child.stdout.pipe(process.stdout); child.on('exit', (code) => { if (code === 0) {