Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Addon postinstall hooks #8700

Merged
merged 13 commits into from
Nov 14, 2019
Merged

CLI: Addon postinstall hooks #8700

merged 13 commits into from
Nov 14, 2019

Conversation

shilman
Copy link
Member

@shilman shilman commented Nov 4, 2019

Issue: #8577

What I did

  • Postinstall utilties for updating presets.js
  • CLI integration for sb add
  • Addon-docs preset update
  • Update documentation (after review)

How to test

I used relative-deps to test this:

npx create-react-app test-postinstall

Then I added the following to package.json:

{
  "devDependencies": {
    "@storybook/addon-actions": "^5.2.5",
    "@storybook/addon-docs": "^5.2.5",
    "@storybook/addon-links": "^5.2.5",
    "@storybook/addons": "^5.2.5",
    "@storybook/cli": "^5.2.5",
    "@storybook/react": "^5.2.5",
    "relative-deps": "^0.2.0"
  },
  "relativeDependencies": {
    "@storybook/cli": "../storybook/lib/cli",
    "@storybook/addon-docs": "../storybook/addons/docs",
    "@storybook/postinstall": "../storybook/lib/postinstall"
  }
}

Then I ran I installed the dependencies:

yarn # install deps
yarn relative-deps

Then I added docs and verified the output in .storybook/presets:

yarn sb add docs

NOTE: For some reason, isOfficialAddon is false, so I had to stub that out. It's possible that the calculation function is broken? Or that using relative-deps screws things up? Or that npm is down?

@vercel
Copy link

vercel bot commented Nov 4, 2019

This pull request is being automatically deployed with ZEIT Now (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://zeit.co/storybook/monorepo/nqi8ry7ox
🌍 Preview: https://monorepo-git-8577-addons-postinstall.storybook.now.sh

@shilman shilman added this to the 5.3.0 milestone Nov 4, 2019
Copy link
Member

@ndelangen ndelangen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you want addons to be capable of rewriting a user's presets.js / configuration after being added by the CLI.

This PR scopes it pretty narrowly to "just preset.js" and only a single codemod on that exact file.

I wonder if we should do the following:

  • write a package that exports a function "to run a codemod on a storybook config file" on.
    // some-addon/postinstall.js
    import { runCodeMod, addPreset, addAddon } from '@storybook/codemod';
    
    // run a codemod with a function
    runCodeMod('preset', ({ api, root }) => {}));
    
    // run a very easy codemod just to add a preset
    addPreset(['typescript', 'sass']);
    
    // run a very easy codemod to add a addon ref in manager
    addAddon('docs');
    
    // users can even decide to take matters into their own hands, and just do some JS in node here
  • Let users use our predefined functions to make it easy for them, but give them the control they'd need to do powerful stuff.

skipMsg = 'unofficial addon';
} else {
const presetsCodemod = require.resolve(
`${getPackageName(addonName, isOfficialAddon)}/postinstall/presets.js`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you expecting other files other then preset.js here?
Why not just make it index.js?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah will add support for other files in future

`${getPackageName(addonName, isOfficialAddon)}/postinstall/presets.js`
);
if (fs.existsSync(presetsCodemod)) {
if (fs.existsSync('.storybook')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess there's no way to know if there's a non-standard configDir?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only way is to ok infer it from package.json which is what chromatic does

if (!fs.existsSync(presetsFile)) {
fs.writeFileSync(presetsFile, '', 'utf8');
}
spawnSync('npx', ['jscodeshift', '-t', presetsCodemod, presetsFile], {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the postinstall is actually a "post-add-modemod". It's limited to be exactly a codemod for presets.js only?

I THINK presets.js can be a .ts file too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope AFAIK it can't

api: any;
}

export function addPreset(preset: string, presetOptions: any, { api, root }: PostinstallContext) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this part of addons? It seems not meant to be part of either the manager or preview's code at all?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't want add-ons to have to take that dependency. You'll notice that this uses dependency injection to avoid needing any extra deps

addons/docs/postinstall/presets.js Outdated Show resolved Hide resolved
Copy link
Member

@ndelangen ndelangen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you want addons to be capable of rewriting a user's presets.js / configuration after being added by the CLI.

This PR scopes it pretty narrowly to "just preset.js" and only a single codemod on that exact file.

I wonder if we should do the following:

  • write a package that exports a function "to run a codemod on a storybook config file" on.
    // some-addon/postinstall.js
    import { runCodeMod, addPreset, addAddon } from '@storybook/codemod';
    
    // run a codemod with a function
    runCodeMod('preset', ({ api, root }) => {}));
    
    // run a very easy codemod just to add a preset
    addPreset(['typescript', 'sass']);
    
    // run a very easy codemod to add a addon ref in manager
    addAddon('docs');
    
    // users can even decide to take matters into their own hands, and just do some JS in node here
  • Let users use our predefined functions to make it easy for them, but give them the control they'd need to do powerful stuff.
  • Run this postinstall.js | postinstall.ts when the package is added via the CLI.

addAddon would ensure the addon is added once to the entry of manager see: f8e6f31#diff-ec8cd75f31bce9dc44ea59d186747551R3-R21

addpreset would do the exact same as above, but obviously to the presets property.

We can deduplicate at runtime too, to keep the codemods even simpler?

Copy link
Member

@ndelangen ndelangen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops duped

@shilman
Copy link
Member Author

shilman commented Nov 4, 2019

@ndelangen I considered that, but the tradeoff here is addon package size & security. In the current PR, jscodeshift is a dep of the CLI. If we add it to the addon, that means that every addon that uses this functionality will need to depend on jscodeshift. Currently it doesn't add any weight to the addon.

The addon has the ability to run any codemod it wants on .storybook/presets.js. And in the near future, will get the same for addons.[tj]s & config.[tj]s, which is pretty flexible.

Copy link
Member

@tmeasday tmeasday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach seems reasonable to me.

@shilman shilman changed the title Addons postinstall hooks CLI: Addon postinstall hooks Nov 12, 2019
@vercel vercel bot temporarily deployed to staging November 14, 2019 03:33 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants