-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
Conversation
This pull request is being automatically deployed with ZEIT Now (learn more). 🔍 Inspect: https://zeit.co/storybook/monorepo/nqi8ry7ox |
There was a problem hiding this 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.
lib/cli/lib/add.js
Outdated
skipMsg = 'unofficial addon'; | ||
} else { | ||
const presetsCodemod = require.resolve( | ||
`${getPackageName(addonName, isOfficialAddon)}/postinstall/presets.js` |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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
lib/cli/lib/add.js
Outdated
`${getPackageName(addonName, isOfficialAddon)}/postinstall/presets.js` | ||
); | ||
if (fs.existsSync(presetsCodemod)) { | ||
if (fs.existsSync('.storybook')) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
lib/cli/lib/add.js
Outdated
if (!fs.existsSync(presetsFile)) { | ||
fs.writeFileSync(presetsFile, '', 'utf8'); | ||
} | ||
spawnSync('npx', ['jscodeshift', '-t', presetsCodemod, presetsFile], { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this 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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops duped
@ndelangen I considered that, but the tradeoff here is addon package size & security. In the current PR, The addon has the ability to run any codemod it wants on |
There was a problem hiding this 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.
Issue: #8577
What I did
sb add
How to test
I used relative-deps to test this:
Then I added the following to
package.json
:Then I ran I installed the dependencies:
Then I added docs and verified the output in
.storybook/presets
:NOTE: For some reason,
isOfficialAddon
isfalse
, so I had to stub that out. It's possible that the calculation function is broken? Or that usingrelative-deps
screws things up? Or thatnpm
is down?