Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/contribute/code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ Otherwise, if it affects the `Manager` (the outermost Storybook `iframe` where t

![Storybook manager preview](../_assets/addons/manager-preview.png)

The `yarn build` commands accepts arguments to help speed up your development workflow:
* `--all` will cause all packages to be built
* `--watch` will enable watch mode (and skip the watch mode prompt)
* `--prod` will build for production (and skip the production mode prompt)
* individual package names can be passed, without the `@storybook/` prefix, e.g. `storybook`, `addon-docs`, etc.

For example, to build Storybook and the docs addon in watch mode, run:

```shell
yarn build --watch storybook addon-docs
```


## Check your work

When you're done coding, add documentation and tests as appropriate. That simplifies the PR review process, which means your code will get merged faster.
Expand Down
124 changes: 54 additions & 70 deletions scripts/build-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
*
* You can pass a list of package names to build, or use the `--all` flag to build all packages.
*
* You can also pass the `--watch` flag to build in watch mode.
* Pass the `--watch` flag to build in watch mode or `--no-watch` to skip the watch mode prompt.
*
* You can also pass the `--prod` flag to build in production mode.
* Pass the `--prod` flag to build in production mode or `--no-prod` to skip the production prompt.
*
* When you pass no package names, you will be prompted to select which packages to build.
*/
Expand All @@ -25,8 +25,20 @@ import { findMostMatchText } from './utils/diff';
import { getCodeWorkspaces } from './utils/workspace';

async function run() {
const packages = (await getCodeWorkspaces()).filter(({ name }) => name !== '@storybook/code');
const packageTasks = packages
const packages = (await getCodeWorkspaces())
.filter(({ name }) => name !== '@storybook/code')
.sort((a) => (a.name === 'storybook' ? -1 : 0)); // Place main package first in option list

const tasks: Record<
string,
{
name: string;
defaultValue: boolean;
suffix: string;
value?: unknown;
location?: string;
}
> = packages
.map((pkg) => {
let suffix = pkg.name.replace('@storybook/', '');
if (pkg.name === '@storybook/cli') {
Expand All @@ -36,102 +48,74 @@ async function run() {
...pkg,
suffix,
defaultValue: false,
helpText: `build only the ${pkg.name} package`,
};
})
.reduce(
(acc, next) => {
acc[next.name] = next;
return acc;
},
{} as Record<
string,
{ name: string; defaultValue: boolean; suffix: string; helpText: string }
>
{} as Record<string, { name: string; defaultValue: boolean; suffix: string }>
);

const tasks: Record<
string,
{
name: string;
defaultValue: boolean;
suffix: string;
helpText: string;
value?: any;
location?: string;
}
> = {
watch: {
name: `watch`,
defaultValue: false,
suffix: '--watch',
helpText: 'build on watch mode',
},
prod: {
name: `prod`,
defaultValue: false,
suffix: '--prod',
helpText: 'build on production mode',
},
...packageTasks,
};

const main = program
.version('5.0.0')
.option('--all', `build everything ${picocolors.gray('(all)')}`);
.allowExcessArguments(true)
.option('--all', `build everything ${picocolors.gray('(all)')}`, false)
.option('--watch', `build in watch mode`)
.option('--prod', `build in production mode`)
.option('--no-watch', `do not build in watch mode`)
.option('--no-prod', `do not build in production mode`);

main.parse(process.argv);

Object.keys(tasks)
.reduce((acc, key) => acc.option(tasks[key].suffix, tasks[key].helpText), main)
.parse(process.argv);
const opts = main.opts();
let watchMode = opts.watch;
let prodMode = opts.prod;

Object.keys(tasks).forEach((key) => {
const opts = program.opts();
// checks if a flag is passed e.g. yarn build --@storybook/addon-docs --watch
const containsFlag = program.args.includes(tasks[key].suffix);
// checks if a flag is passed e.g. yarn build addon-docs --watch
const containsFlag = main.args.includes(tasks[key].suffix);
tasks[key].value = containsFlag || opts.all;
});

let watchMode = process.argv.includes('--watch');
let prodMode = process.argv.includes('--prod');
let selection = Object.keys(tasks)
.map((key) => tasks[key])
.filter((item) => !['watch', 'prod'].includes(item.name) && item.value === true);

// user has passed invalid package name(s) - try to guess the correct package name(s)
if ((!selection.length && main.args.length >= 1) || selection.length !== main.args.length) {
const suffixList = Object.values(tasks)
.filter((t) => t.name.includes('@storybook'))
.map((t) => t.suffix);

for (const arg of main.args) {
if (!suffixList.includes(arg)) {
const matchText = findMostMatchText(suffixList, arg);

if (matchText) {
console.log(
`${picocolors.red('Error')}: ${picocolors.cyan(
arg
)} is not a valid package name, Did you mean ${picocolors.cyan(matchText)}?`
);
}
let selection = Object.values(tasks).filter((item) => item.value === true);

// check for invalid package name(s) and try to guess the correct package name(s)
const suffixList = Object.values(tasks).map((t) => t.suffix);
let hasInvalidName = false;

for (const arg of main.args) {
if (!suffixList.includes(arg)) {
const matchText = findMostMatchText(suffixList, arg);

if (matchText) {
hasInvalidName = true;
process.stderr.write(
`${picocolors.red('Error')}: ${picocolors.cyan(
arg
)} is not a valid package name, Did you mean ${picocolors.cyan(matchText)}?\n`
);
}
}
}

process.exit(0);
if (hasInvalidName) {
process.exit(1);
}
Comment thread
Sidnioulz marked this conversation as resolved.

if (!selection.length) {
selection = await prompts(
[
{
watchMode === undefined && {
type: 'toggle',
name: 'watch',
message: 'Start in watch mode',
initial: false,
active: 'yes',
inactive: 'no',
},
{
prodMode === undefined && {
type: 'toggle',
name: 'prod',
message: 'Start in production mode',
Expand All @@ -144,7 +128,7 @@ async function run() {
message: 'Select the packages to build',
name: 'todo',
min: 1,
hint: 'You can also run directly with package name like `yarn build core`, or `yarn build --all` for all packages!',
hint: 'You can also run directly with package name like `yarn build storybook`, or `yarn build --all` for all packages!',
// @ts-expect-error @types incomplete
optionsPerPage: windowSize.height - 3, // 3 lines for extra info
choices: packages.map(({ name: key }) => ({
Expand All @@ -162,7 +146,7 @@ async function run() {
});
}

console.log('Building selected packages...');
process.stdout.write('Building selected packages...\n');
let lastName = '';

selection.forEach(async (v) => {
Expand Down