2022-10-05 15:49:58 +11:00
|
|
|
// This file requires many imports from `../code`, which requires both an install and bootstrap of
|
|
|
|
// the repo to work properly. So we load it async in the task runner *after* those steps.
|
|
|
|
|
2023-04-13 09:46:47 +04:00
|
|
|
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
2023-01-12 11:42:31 +01:00
|
|
|
import {
|
|
|
|
copy,
|
|
|
|
ensureSymlink,
|
|
|
|
ensureDir,
|
|
|
|
existsSync,
|
|
|
|
pathExists,
|
|
|
|
readJson,
|
|
|
|
writeJson,
|
|
|
|
} from 'fs-extra';
|
2022-10-05 11:25:31 +11:00
|
|
|
import { join, resolve, sep } from 'path';
|
|
|
|
|
2023-01-22 13:50:43 +01:00
|
|
|
import slash from 'slash';
|
2023-01-11 09:26:11 +01:00
|
|
|
import type { Task } from '../task';
|
2022-10-05 11:25:31 +11:00
|
|
|
import { executeCLIStep, steps } from '../utils/cli-step';
|
2023-05-10 09:10:24 -04:00
|
|
|
import {
|
|
|
|
installYarn2,
|
|
|
|
configureYarn2ForVerdaccio,
|
|
|
|
addPackageResolutions,
|
|
|
|
addWorkaroundResolutions,
|
|
|
|
} from '../utils/yarn';
|
2022-10-05 11:25:31 +11:00
|
|
|
import { exec } from '../utils/exec';
|
2022-11-07 17:20:42 +11:00
|
|
|
import type { ConfigFile } from '../../code/lib/csf-tools';
|
|
|
|
import { writeConfig } from '../../code/lib/csf-tools';
|
2022-10-05 11:25:31 +11:00
|
|
|
import { filterExistsInCodeDir } from '../utils/filterExistsInCodeDir';
|
|
|
|
import { findFirstPath } from '../utils/paths';
|
|
|
|
import { detectLanguage } from '../../code/lib/cli/src/detect';
|
|
|
|
import { SupportedLanguage } from '../../code/lib/cli/src/project_types';
|
2022-10-10 22:35:41 +11:00
|
|
|
import { updatePackageScripts } from '../utils/package-json';
|
2022-10-05 11:25:31 +11:00
|
|
|
import { addPreviewAnnotations, readMainConfig } from '../utils/main-js';
|
|
|
|
import { JsPackageManagerFactory } from '../../code/lib/cli/src/js-package-manager';
|
|
|
|
import { workspacePath } from '../utils/workspace';
|
|
|
|
import { babelParse } from '../../code/lib/csf-tools/src/babelParse';
|
2023-03-29 12:32:23 +02:00
|
|
|
import { CODE_DIRECTORY, REPROS_DIRECTORY } from '../utils/constants';
|
2022-10-05 11:25:31 +11:00
|
|
|
|
|
|
|
const logger = console;
|
|
|
|
|
2022-10-10 21:43:06 +11:00
|
|
|
export const essentialsAddons = [
|
|
|
|
'actions',
|
|
|
|
'backgrounds',
|
|
|
|
'controls',
|
|
|
|
'docs',
|
|
|
|
'highlight',
|
|
|
|
'measure',
|
|
|
|
'outline',
|
|
|
|
'toolbars',
|
|
|
|
'viewport',
|
|
|
|
];
|
|
|
|
|
2023-02-15 12:16:18 +08:00
|
|
|
export const create: Task['run'] = async ({ key, template, sandboxDir }, { dryRun, debug }) => {
|
2022-10-05 11:25:31 +11:00
|
|
|
const parentDir = resolve(sandboxDir, '..');
|
|
|
|
await ensureDir(parentDir);
|
|
|
|
|
2022-11-15 20:09:08 +11:00
|
|
|
if ('inDevelopment' in template && template.inDevelopment) {
|
2023-03-29 12:05:38 +02:00
|
|
|
const srcDir = join(REPROS_DIRECTORY, key, 'after-storybook');
|
2022-10-05 11:25:31 +11:00
|
|
|
if (!existsSync(srcDir)) {
|
2022-11-15 20:09:08 +11:00
|
|
|
throw new Error(`Missing repro directory '${srcDir}', did the generate task run?`);
|
2022-10-05 11:25:31 +11:00
|
|
|
}
|
|
|
|
await copy(srcDir, sandboxDir);
|
|
|
|
} else {
|
|
|
|
await executeCLIStep(steps.repro, {
|
|
|
|
argument: key,
|
2023-04-24 20:40:05 +02:00
|
|
|
optionValues: { output: sandboxDir, branch: 'next', init: false, debug },
|
2022-10-05 11:25:31 +11:00
|
|
|
cwd: parentDir,
|
|
|
|
dryRun,
|
|
|
|
debug,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-02-15 12:16:18 +08:00
|
|
|
export const install: Task['run'] = async (
|
|
|
|
{ sandboxDir, template },
|
|
|
|
{ link, dryRun, debug, addon: addons, skipTemplateStories }
|
|
|
|
) => {
|
2022-10-05 11:25:31 +11:00
|
|
|
const cwd = sandboxDir;
|
|
|
|
await installYarn2({ cwd, dryRun, debug });
|
|
|
|
|
|
|
|
if (link) {
|
|
|
|
await executeCLIStep(steps.link, {
|
|
|
|
argument: sandboxDir,
|
2023-03-29 12:32:23 +02:00
|
|
|
cwd: CODE_DIRECTORY,
|
2022-10-05 11:25:31 +11:00
|
|
|
optionValues: { local: true, start: false },
|
|
|
|
dryRun,
|
|
|
|
debug,
|
|
|
|
});
|
2023-05-10 09:10:24 -04:00
|
|
|
await addWorkaroundResolutions({ cwd, dryRun, debug });
|
2022-10-05 11:25:31 +11:00
|
|
|
} else {
|
|
|
|
// We need to add package resolutions to ensure that we only ever install the latest version
|
|
|
|
// of any storybook packages as verdaccio is not able to both proxy to npm and publish over
|
|
|
|
// the top. In theory this could mask issues where different versions cause problems.
|
|
|
|
await addPackageResolutions({ cwd, dryRun, debug });
|
|
|
|
await configureYarn2ForVerdaccio({ cwd, dryRun, debug });
|
|
|
|
|
|
|
|
await exec(
|
|
|
|
'yarn install',
|
|
|
|
{ cwd },
|
|
|
|
{
|
2022-12-06 09:47:39 +01:00
|
|
|
debug,
|
2022-10-05 11:25:31 +11:00
|
|
|
dryRun,
|
|
|
|
startMessage: `⬇️ Installing local dependencies`,
|
|
|
|
errorMessage: `🚨 Installing local dependencies failed`,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-05-09 00:28:16 +08:00
|
|
|
let extra = {};
|
|
|
|
if (template.expected.renderer === '@storybook/html') extra = { type: 'html' };
|
|
|
|
else if (template.expected.renderer === '@storybook/server') extra = { type: 'server' };
|
2022-12-06 14:34:17 +01:00
|
|
|
|
|
|
|
await executeCLIStep(steps.init, {
|
|
|
|
cwd,
|
2022-12-06 15:17:28 +01:00
|
|
|
optionValues: { debug, yes: true, ...extra },
|
2022-12-06 14:34:17 +01:00
|
|
|
dryRun,
|
|
|
|
debug,
|
|
|
|
});
|
2022-12-06 09:40:48 +01:00
|
|
|
|
2022-10-05 11:25:31 +11:00
|
|
|
logger.info(`🔢 Adding package scripts:`);
|
2023-02-14 17:02:52 +01:00
|
|
|
|
|
|
|
const nodeOptions = [
|
|
|
|
...(process.env.NODE_OPTIONS || '').split(' '),
|
|
|
|
'--preserve-symlinks',
|
|
|
|
'--preserve-symlinks-main',
|
|
|
|
].filter(Boolean);
|
|
|
|
|
|
|
|
const pnp = await pathExists(join(cwd, '.pnp.cjs')).catch(() => {});
|
|
|
|
if (pnp && !nodeOptions.find((s) => s.includes('--require'))) {
|
|
|
|
nodeOptions.push('--require ./.pnp.cjs');
|
|
|
|
}
|
|
|
|
|
|
|
|
const nodeOptionsString = nodeOptions.join(' ');
|
|
|
|
const prefix = `NODE_OPTIONS="${nodeOptionsString}" STORYBOOK_TELEMETRY_URL="http://localhost:6007/event-log"`;
|
|
|
|
|
2022-10-10 22:35:41 +11:00
|
|
|
await updatePackageScripts({
|
2022-10-05 11:25:31 +11:00
|
|
|
cwd,
|
2023-02-14 17:02:52 +01:00
|
|
|
prefix,
|
2022-10-05 11:25:31 +11:00
|
|
|
});
|
2023-01-12 11:42:31 +01:00
|
|
|
|
|
|
|
switch (template.expected.framework) {
|
|
|
|
case '@storybook/angular':
|
|
|
|
await prepareAngularSandbox(cwd);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
2023-02-15 12:16:18 +08:00
|
|
|
|
|
|
|
if (!skipTemplateStories) {
|
|
|
|
for (const addon of addons) {
|
|
|
|
const addonName = `@storybook/addon-${addon}`;
|
|
|
|
await executeCLIStep(steps.add, { argument: addonName, cwd, dryRun, debug });
|
|
|
|
}
|
|
|
|
}
|
2022-10-05 11:25:31 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
// Ensure that sandboxes can refer to story files defined in `code/`.
|
|
|
|
// Most WP-based build systems will not compile files outside of the project root or 'src/` or
|
|
|
|
// similar. Plus they aren't guaranteed to handle TS files. So we need to patch in esbuild
|
|
|
|
// loader for such files. NOTE this isn't necessary for Vite, as far as we know.
|
|
|
|
function addEsbuildLoaderToStories(mainConfig: ConfigFile) {
|
|
|
|
// NOTE: the test regexp here will apply whether the path is symlink-preserved or otherwise
|
2022-10-10 17:15:43 +11:00
|
|
|
const esbuildLoaderPath = require.resolve('../../code/node_modules/esbuild-loader');
|
|
|
|
const storiesMdxLoaderPath = require.resolve(
|
2022-10-15 14:59:51 +08:00
|
|
|
'../../code/node_modules/@storybook/mdx2-csf/loader'
|
2022-10-10 17:15:43 +11:00
|
|
|
);
|
2022-10-10 16:56:47 +11:00
|
|
|
const babelLoaderPath = require.resolve('babel-loader');
|
|
|
|
const jsxPluginPath = require.resolve('@babel/plugin-transform-react-jsx');
|
2022-10-05 11:25:31 +11:00
|
|
|
const webpackFinalCode = `
|
|
|
|
(config) => ({
|
|
|
|
...config,
|
|
|
|
module: {
|
2022-12-08 16:35:47 +01:00
|
|
|
...config.module,
|
2022-10-05 11:25:31 +11:00
|
|
|
rules: [
|
|
|
|
// Ensure esbuild-loader applies to all files in ./template-stories
|
|
|
|
{
|
|
|
|
test: [/\\/template-stories\\//],
|
2022-10-10 16:56:47 +11:00
|
|
|
exclude: [/\\.mdx$/],
|
|
|
|
loader: '${esbuildLoaderPath}',
|
2022-10-05 11:25:31 +11:00
|
|
|
options: {
|
|
|
|
loader: 'tsx',
|
|
|
|
target: 'es2015',
|
|
|
|
},
|
|
|
|
},
|
2022-10-10 16:56:47 +11:00
|
|
|
// Handle MDX files per the addon-docs presets (ish)
|
|
|
|
{
|
|
|
|
test: [/\\/template-stories\\//],
|
|
|
|
include: [/\\.stories\\.mdx$/],
|
|
|
|
use: [
|
|
|
|
{
|
|
|
|
loader: '${babelLoaderPath}',
|
|
|
|
options: {
|
|
|
|
babelrc: false,
|
|
|
|
configFile: false,
|
|
|
|
plugins: ['${jsxPluginPath}'],
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
loader: '${storiesMdxLoaderPath}',
|
|
|
|
options: {
|
|
|
|
skipCsf: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
test: [/\\/template-stories\\//],
|
|
|
|
include: [/\\.mdx$/],
|
|
|
|
exclude: [/\\.stories\\.mdx$/],
|
|
|
|
use: [
|
|
|
|
{
|
|
|
|
loader: '${babelLoaderPath}',
|
|
|
|
options: {
|
|
|
|
babelrc: false,
|
|
|
|
configFile: false,
|
|
|
|
plugins: ['${jsxPluginPath}'],
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
loader: '${storiesMdxLoaderPath}',
|
|
|
|
options: {
|
|
|
|
skipCsf: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
},
|
2022-10-05 11:25:31 +11:00
|
|
|
// Ensure no other loaders from the framework apply
|
|
|
|
...config.module.rules.map(rule => ({
|
|
|
|
...rule,
|
|
|
|
exclude: [/\\/template-stories\\//].concat(rule.exclude || []),
|
|
|
|
})),
|
|
|
|
],
|
|
|
|
},
|
|
|
|
})`;
|
|
|
|
mainConfig.setFieldNode(
|
|
|
|
['webpackFinal'],
|
|
|
|
babelParse(webpackFinalCode).program.body[0].expression
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:04 +02:00
|
|
|
/*
|
|
|
|
Recompile optimized deps on each startup, so you can change @storybook/* packages and not
|
|
|
|
have to clear caches.
|
|
|
|
And allow source directories to complement any existing allow patterns
|
|
|
|
(".storybook" is already being allowed by builder-vite)
|
|
|
|
*/
|
|
|
|
function setSandboxViteFinal(mainConfig: ConfigFile) {
|
2022-10-05 11:25:31 +11:00
|
|
|
const viteFinalCode = `
|
|
|
|
(config) => ({
|
|
|
|
...config,
|
2022-10-13 20:30:04 +02:00
|
|
|
optimizeDeps: { ...config.optimizeDeps, force: true },
|
|
|
|
server: {
|
|
|
|
...config.server,
|
|
|
|
fs: {
|
|
|
|
...config.server?.fs,
|
2023-02-09 13:36:11 +11:00
|
|
|
allow: ['stories', 'src', 'template-stories', 'node_modules', ...(config.server?.fs?.allow || [])],
|
2022-10-13 20:30:04 +02:00
|
|
|
},
|
2022-10-05 11:25:31 +11:00
|
|
|
},
|
|
|
|
})`;
|
2023-03-29 12:19:27 +02:00
|
|
|
mainConfig.setFieldNode(['viteFinal'], babelParse(viteFinalCode).program.body[0].expression);
|
2022-10-05 11:25:31 +11:00
|
|
|
}
|
|
|
|
|
2022-11-04 16:16:11 +11:00
|
|
|
// Update the stories field to ensure that no TS files
|
|
|
|
// that are linked from the renderer are picked up in non-TS projects
|
|
|
|
function updateStoriesField(mainConfig: ConfigFile, isJs: boolean) {
|
|
|
|
const stories = mainConfig.getFieldValue(['stories']) as string[];
|
|
|
|
|
|
|
|
// If the project is a JS project, let's make sure any linked in TS stories from the
|
|
|
|
// renderer inside src|stories are simply ignored.
|
|
|
|
const updatedStories = isJs
|
|
|
|
? stories.map((specifier) => specifier.replace('js|jsx|ts|tsx', 'js|jsx'))
|
|
|
|
: stories;
|
|
|
|
|
|
|
|
mainConfig.setFieldValue(['stories'], [...updatedStories]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a stories field entry for the passed symlink
|
|
|
|
function addStoriesEntry(mainConfig: ConfigFile, path: string) {
|
|
|
|
const stories = mainConfig.getFieldValue(['stories']) as string[];
|
|
|
|
|
|
|
|
const entry = {
|
2023-01-22 13:50:43 +01:00
|
|
|
directory: slash(join('../template-stories', path)),
|
|
|
|
titlePrefix: slash(path),
|
2022-11-07 11:48:29 +11:00
|
|
|
files: '**/*.@(mdx|stories.@(js|jsx|ts|tsx))',
|
2022-11-04 16:16:11 +11:00
|
|
|
};
|
2022-11-14 23:58:48 +08:00
|
|
|
|
2022-11-04 16:16:11 +11:00
|
|
|
mainConfig.setFieldValue(['stories'], [...stories, entry]);
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:48:48 +02:00
|
|
|
function getStoriesFolderWithVariant(variant?: string, folder = 'stories') {
|
2022-11-30 13:30:24 +01:00
|
|
|
return variant ? `${folder}_${variant}` : folder;
|
|
|
|
}
|
|
|
|
|
2022-10-05 11:25:31 +11:00
|
|
|
// packageDir is eg 'renderers/react', 'addons/actions'
|
|
|
|
async function linkPackageStories(
|
|
|
|
packageDir: string,
|
2022-11-30 13:30:24 +01:00
|
|
|
{ mainConfig, cwd, linkInDir }: { mainConfig: ConfigFile; cwd: string; linkInDir?: string },
|
2023-04-25 08:48:48 +02:00
|
|
|
variant?: string
|
2022-10-05 11:25:31 +11:00
|
|
|
) {
|
2023-04-25 08:48:48 +02:00
|
|
|
const storiesFolderName = variant ? getStoriesFolderWithVariant(variant) : 'stories';
|
2023-03-29 12:32:23 +02:00
|
|
|
const source = join(CODE_DIRECTORY, packageDir, 'template', storiesFolderName);
|
2022-10-05 11:25:31 +11:00
|
|
|
// By default we link `stories` directories
|
|
|
|
// e.g '../../../code/lib/store/template/stories' to 'template-stories/lib/store'
|
|
|
|
// if the directory <code>/lib/store/template/stories exists
|
|
|
|
//
|
|
|
|
// The files must be linked in the cwd, in order to ensure that any dependencies they
|
|
|
|
// reference are resolved in the cwd. In particular 'react' resolved by MDX files.
|
|
|
|
const target = linkInDir
|
2023-04-25 08:48:48 +02:00
|
|
|
? resolve(linkInDir, variant ? getStoriesFolderWithVariant(variant, packageDir) : packageDir)
|
2022-10-05 11:25:31 +11:00
|
|
|
: resolve(cwd, 'template-stories', packageDir);
|
2022-11-30 13:30:24 +01:00
|
|
|
|
2022-10-05 11:25:31 +11:00
|
|
|
await ensureSymlink(source, target);
|
|
|
|
|
2023-01-20 09:42:30 +01:00
|
|
|
if (!linkInDir) {
|
|
|
|
addStoriesEntry(mainConfig, packageDir);
|
|
|
|
}
|
2022-11-04 16:16:11 +11:00
|
|
|
|
2022-10-05 11:25:31 +11:00
|
|
|
// Add `previewAnnotation` entries of the form
|
2022-10-10 13:05:51 +11:00
|
|
|
// './template-stories/lib/store/preview.[tj]s'
|
|
|
|
// if the file <code>/lib/store/template/stories/preview.[jt]s exists
|
|
|
|
await Promise.all(
|
|
|
|
['js', 'ts'].map(async (ext) => {
|
|
|
|
const previewFile = `preview.${ext}`;
|
2023-03-29 12:32:23 +02:00
|
|
|
const previewPath = join(
|
|
|
|
CODE_DIRECTORY,
|
|
|
|
packageDir,
|
|
|
|
'template',
|
|
|
|
storiesFolderName,
|
|
|
|
previewFile
|
|
|
|
);
|
2022-10-10 13:05:51 +11:00
|
|
|
if (await pathExists(previewPath)) {
|
2022-10-10 20:25:39 +08:00
|
|
|
let storiesDir = 'template-stories';
|
|
|
|
if (linkInDir) {
|
2023-04-27 10:56:23 +02:00
|
|
|
storiesDir = (await pathExists(join(cwd, 'src/stories'))) ? 'src/stories' : 'stories';
|
2022-10-10 20:25:39 +08:00
|
|
|
}
|
2023-04-27 10:56:23 +02:00
|
|
|
addPreviewAnnotations(mainConfig, [
|
|
|
|
`./${join(storiesDir, variant ? `${packageDir}_${variant}` : packageDir, previewFile)}`,
|
|
|
|
]);
|
2022-10-10 13:05:51 +11:00
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
2022-10-05 11:25:31 +11:00
|
|
|
}
|
|
|
|
|
2023-05-05 12:34:08 +02:00
|
|
|
async function addExtraDependencies({
|
2022-10-05 11:25:31 +11:00
|
|
|
cwd,
|
|
|
|
dryRun,
|
|
|
|
debug,
|
|
|
|
}: {
|
|
|
|
cwd: string;
|
|
|
|
dryRun: boolean;
|
|
|
|
debug: boolean;
|
|
|
|
}) {
|
2022-10-10 21:43:06 +11:00
|
|
|
// web-components doesn't install '@storybook/testing-library' by default
|
2023-04-11 21:29:24 +08:00
|
|
|
const extraDeps = [
|
|
|
|
'@storybook/jest@future',
|
|
|
|
'@storybook/testing-library@future',
|
|
|
|
'@storybook/test-runner@future',
|
|
|
|
];
|
2022-10-05 11:25:31 +11:00
|
|
|
if (debug) logger.log('🎁 Adding extra deps', extraDeps);
|
|
|
|
if (!dryRun) {
|
2022-10-10 19:34:52 -04:00
|
|
|
const packageManager = JsPackageManagerFactory.getPackageManager({}, cwd);
|
2023-05-05 12:34:08 +02:00
|
|
|
await packageManager.addDependencies({ installAsDevDependencies: true }, extraDeps);
|
2022-10-05 11:25:31 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const addStories: Task['run'] = async (
|
2023-01-10 18:55:16 +01:00
|
|
|
{ sandboxDir, template, key },
|
2022-10-10 21:43:06 +11:00
|
|
|
{ addon: extraAddons, dryRun, debug }
|
2022-10-05 11:25:31 +11:00
|
|
|
) => {
|
2023-02-14 17:02:52 +01:00
|
|
|
logger.log('💃 adding stories');
|
2022-10-05 11:25:31 +11:00
|
|
|
const cwd = sandboxDir;
|
|
|
|
const storiesPath = await findFirstPath([join('src', 'stories'), 'stories'], { cwd });
|
|
|
|
|
|
|
|
const mainConfig = await readMainConfig({ cwd });
|
|
|
|
|
2022-11-04 16:16:11 +11:00
|
|
|
// Ensure that we match the right stories in the stories directory
|
|
|
|
const packageJson = await import(join(cwd, 'package.json'));
|
2022-11-14 23:58:48 +08:00
|
|
|
updateStoriesField(mainConfig, detectLanguage(packageJson) === SupportedLanguage.JAVASCRIPT);
|
2022-11-04 16:16:11 +11:00
|
|
|
|
2023-05-09 00:28:16 +08:00
|
|
|
const isCoreRenderer =
|
|
|
|
template.expected.renderer.startsWith('@storybook/') &&
|
|
|
|
template.expected.renderer !== '@storybook/server';
|
2023-04-25 08:48:48 +02:00
|
|
|
|
|
|
|
const sandboxSpecificStoriesFolder = key.replaceAll('/', '-');
|
|
|
|
const storiesVariantFolder = getStoriesFolderWithVariant(sandboxSpecificStoriesFolder);
|
|
|
|
|
2023-01-18 08:31:12 -05:00
|
|
|
if (isCoreRenderer) {
|
|
|
|
// Link in the template/components/index.js from store, the renderer and the addons
|
|
|
|
const rendererPath = await workspacePath('renderer', template.expected.renderer);
|
|
|
|
await ensureSymlink(
|
2023-03-29 12:32:23 +02:00
|
|
|
join(CODE_DIRECTORY, rendererPath, 'template', 'components'),
|
2023-01-18 08:31:12 -05:00
|
|
|
resolve(cwd, storiesPath, 'components')
|
|
|
|
);
|
|
|
|
addPreviewAnnotations(mainConfig, [`.${sep}${join(storiesPath, 'components')}`]);
|
2022-11-30 13:30:24 +01:00
|
|
|
|
2023-01-18 08:31:12 -05:00
|
|
|
// Add stories for the renderer. NOTE: these *do* need to be processed by the framework build system
|
|
|
|
await linkPackageStories(rendererPath, {
|
2022-10-19 19:20:47 +02:00
|
|
|
mainConfig,
|
|
|
|
cwd,
|
|
|
|
linkInDir: resolve(cwd, storiesPath),
|
|
|
|
});
|
2023-04-25 08:48:48 +02:00
|
|
|
|
|
|
|
if (
|
|
|
|
await pathExists(
|
|
|
|
resolve(CODE_DIRECTORY, rendererPath, join('template', storiesVariantFolder))
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
await linkPackageStories(
|
|
|
|
rendererPath,
|
|
|
|
{
|
|
|
|
mainConfig,
|
|
|
|
cwd,
|
|
|
|
linkInDir: resolve(cwd, storiesPath),
|
|
|
|
},
|
|
|
|
sandboxSpecificStoriesFolder
|
|
|
|
);
|
|
|
|
}
|
2022-10-19 19:20:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-18 08:31:12 -05:00
|
|
|
const isCoreFramework = template.expected.framework.startsWith('@storybook/');
|
2022-11-30 13:30:24 +01:00
|
|
|
|
2023-01-18 08:31:12 -05:00
|
|
|
if (isCoreFramework) {
|
|
|
|
const frameworkPath = await workspacePath('frameworks', template.expected.framework);
|
|
|
|
|
|
|
|
// Add stories for the framework if it has one. NOTE: these *do* need to be processed by the framework build system
|
2023-03-29 12:32:23 +02:00
|
|
|
if (await pathExists(resolve(CODE_DIRECTORY, frameworkPath, join('template', 'stories')))) {
|
2023-01-18 08:31:12 -05:00
|
|
|
await linkPackageStories(frameworkPath, {
|
2022-11-30 13:30:24 +01:00
|
|
|
mainConfig,
|
|
|
|
cwd,
|
|
|
|
linkInDir: resolve(cwd, storiesPath),
|
2023-01-18 08:31:12 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:48:48 +02:00
|
|
|
console.log({ sandboxSpecificStoriesFolder, storiesVariantFolder });
|
2023-01-18 08:31:12 -05:00
|
|
|
|
2023-03-29 12:32:23 +02:00
|
|
|
if (
|
|
|
|
await pathExists(
|
|
|
|
resolve(CODE_DIRECTORY, frameworkPath, join('template', storiesVariantFolder))
|
|
|
|
)
|
|
|
|
) {
|
2023-01-18 08:31:12 -05:00
|
|
|
await linkPackageStories(
|
|
|
|
frameworkPath,
|
|
|
|
{
|
|
|
|
mainConfig,
|
|
|
|
cwd,
|
|
|
|
linkInDir: resolve(cwd, storiesPath),
|
|
|
|
},
|
2023-04-25 08:48:48 +02:00
|
|
|
sandboxSpecificStoriesFolder
|
2023-01-18 08:31:12 -05:00
|
|
|
);
|
|
|
|
}
|
2022-11-30 13:30:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-20 09:42:30 +01:00
|
|
|
if (isCoreRenderer) {
|
|
|
|
// Add stories for lib/store (and addons below). NOTE: these stories will be in the
|
|
|
|
// template-stories folder and *not* processed by the framework build config (instead by esbuild-loader)
|
|
|
|
await linkPackageStories(await workspacePath('core package', '@storybook/store'), {
|
|
|
|
mainConfig,
|
|
|
|
cwd,
|
|
|
|
});
|
|
|
|
}
|
2022-10-05 11:25:31 +11:00
|
|
|
|
2023-02-15 11:47:17 +01:00
|
|
|
const mainAddons = (mainConfig.getSafeFieldValue(['addons']) || []).reduce(
|
|
|
|
(acc: string[], addon: any) => {
|
|
|
|
const name = typeof addon === 'string' ? addon : addon.name;
|
|
|
|
const match = /@storybook\/addon-(.*)/.exec(name);
|
|
|
|
if (!match) return acc;
|
|
|
|
const suffix = match[1];
|
|
|
|
if (suffix === 'essentials') {
|
|
|
|
return [...acc, ...essentialsAddons];
|
|
|
|
}
|
|
|
|
return [...acc, suffix];
|
|
|
|
},
|
|
|
|
[]
|
|
|
|
);
|
2022-10-10 21:43:06 +11:00
|
|
|
|
2022-10-05 11:25:31 +11:00
|
|
|
const addonDirs = await Promise.all(
|
2022-10-10 21:43:06 +11:00
|
|
|
[...mainAddons, ...extraAddons].map(async (addon) =>
|
|
|
|
workspacePath('addon', `@storybook/addon-${addon}`)
|
2022-10-05 11:25:31 +11:00
|
|
|
)
|
|
|
|
);
|
2022-10-10 21:43:06 +11:00
|
|
|
|
2023-01-20 09:42:30 +01:00
|
|
|
if (isCoreRenderer) {
|
|
|
|
const existingStories = await filterExistsInCodeDir(addonDirs, join('template', 'stories'));
|
2023-01-24 17:33:34 +11:00
|
|
|
for (const packageDir of existingStories) {
|
|
|
|
await linkPackageStories(packageDir, { mainConfig, cwd });
|
|
|
|
}
|
2022-10-05 11:25:31 +11:00
|
|
|
|
2023-01-20 09:42:30 +01:00
|
|
|
// Add some extra settings (see above for what these do)
|
|
|
|
if (template.expected.builder === '@storybook/builder-webpack5') {
|
|
|
|
addEsbuildLoaderToStories(mainConfig);
|
|
|
|
}
|
|
|
|
}
|
2022-10-05 11:25:31 +11:00
|
|
|
|
|
|
|
// Some addon stories require extra dependencies
|
2023-05-05 12:34:08 +02:00
|
|
|
await addExtraDependencies({ cwd, dryRun, debug });
|
2022-10-06 13:57:17 +11:00
|
|
|
|
2023-01-10 18:56:04 +01:00
|
|
|
await writeConfig(mainConfig);
|
|
|
|
};
|
2022-12-02 13:09:57 +11:00
|
|
|
|
2023-01-10 18:56:04 +01:00
|
|
|
export const extendMain: Task['run'] = async ({ template, sandboxDir }) => {
|
|
|
|
logger.log('📝 Extending main.js');
|
|
|
|
const mainConfig = await readMainConfig({ cwd: sandboxDir });
|
2023-01-12 10:12:20 +01:00
|
|
|
const templateConfig = template.modifications?.mainConfig || {};
|
2023-01-10 18:56:04 +01:00
|
|
|
const configToAdd = {
|
|
|
|
...templateConfig,
|
|
|
|
features: {
|
|
|
|
...templateConfig.features,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
Object.entries(configToAdd).forEach(([field, value]) => mainConfig.setFieldValue([field], value));
|
|
|
|
|
|
|
|
if (template.expected.builder === '@storybook/builder-vite') setSandboxViteFinal(mainConfig);
|
2022-10-06 13:57:17 +11:00
|
|
|
await writeConfig(mainConfig);
|
2022-10-05 11:25:31 +11:00
|
|
|
};
|
2023-01-12 11:42:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets compodoc option in angular.json projects to false. We have to generate compodoc
|
|
|
|
* manually to avoid symlink issues related to the template-stories folder.
|
|
|
|
* In a second step a docs:json script is placed into the package.json to generate the
|
|
|
|
* Compodoc documentation.json, which respects symlinks
|
|
|
|
* */
|
|
|
|
async function prepareAngularSandbox(cwd: string) {
|
|
|
|
const angularJson = await readJson(join(cwd, 'angular.json'));
|
|
|
|
|
|
|
|
Object.keys(angularJson.projects).forEach((projectName: string) => {
|
|
|
|
angularJson.projects[projectName].architect.storybook.options.compodoc = false;
|
|
|
|
angularJson.projects[projectName].architect['build-storybook'].options.compodoc = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
await writeJson(join(cwd, 'angular.json'), angularJson, { spaces: 2 });
|
|
|
|
|
|
|
|
const packageJsonPath = join(cwd, 'package.json');
|
|
|
|
const packageJson = await readJson(packageJsonPath);
|
|
|
|
|
|
|
|
packageJson.scripts = {
|
|
|
|
...packageJson.scripts,
|
|
|
|
'docs:json': 'DIR=$PWD; cd ../../scripts; yarn ts-node combine-compodoc $DIR',
|
|
|
|
storybook: `yarn docs:json && ${packageJson.scripts.storybook}`,
|
|
|
|
'build-storybook': `yarn docs:json && ${packageJson.scripts['build-storybook']}`,
|
|
|
|
};
|
|
|
|
|
|
|
|
await writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
|
|
}
|