Create postinstall library for addons

This commit is contained in:
Michael Shilman 2019-11-12 18:01:42 +08:00
parent a001fe4cd8
commit 4c9b100363
24 changed files with 121 additions and 39 deletions

View File

@ -48,6 +48,7 @@
"@storybook/addons": "5.3.0-alpha.42",
"@storybook/api": "5.3.0-alpha.42",
"@storybook/components": "5.3.0-alpha.42",
"@storybook/postinstall": "5.3.0-alpha.42",
"@storybook/router": "5.3.0-alpha.42",
"@storybook/source-loader": "5.3.0-alpha.42",
"@storybook/theming": "5.3.0-alpha.42",

View File

@ -1,9 +1,7 @@
const fs = require('fs');
const { addPreset, getFrameworks } = require('@storybook/addons');
import fs from 'fs';
import { presetsAddPreset, getFrameworks } from '@storybook/postinstall';
// eslint-disable-next-line import/no-extraneous-dependencies
const { logger } = require('@storybook/node-logger');
const SUPPORTED_FRAMEWORKS = ['angular', 'html', 'react', 'vue', 'web-components'];
import { logger } from '@storybook/node-logger';
export default function transformer(file, api) {
const packageJson = JSON.parse(fs.readFileSync('./package.json'));
@ -14,19 +12,13 @@ export default function transformer(file, api) {
let presetOptions = null;
if (frameworks.length !== 1) {
err = `${frameworks.length === 0 ? 'No' : 'Multiple'} frameworks found: ${frameworks}`;
} else {
// eslint-disable-next-line prefer-destructuring
framework = frameworks[0];
if (!SUPPORTED_FRAMEWORKS.includes(framework)) {
err = `Unsupported framework: '${framework}'`;
}
}
if (err) {
logger.error(`${err}, please configure '@storybook/addon-docs' manually.`);
return file.source;
}
// eslint-disable-next-line prefer-destructuring
framework = frameworks[0];
const { dependencies, devDependencies } = packageJson;
if (
framework === 'react' &&
@ -41,7 +33,7 @@ export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
addPreset(`@storybook/addon-docs/${framework}/preset`, presetOptions, { root, api });
presetsAddPreset(`@storybook/addon-docs/preset`, presetOptions, { root, api });
return root.toSource();
}

View File

@ -36,9 +36,7 @@
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"@hypnosphi/jscodeshift": "^0.6.4",
"@types/util-deprecate": "^1.0.0",
"jest-specific-snapshot": "^2.0.0"
"@types/util-deprecate": "^1.0.0"
},
"publishConfig": {
"access": "public"

View File

@ -1,2 +0,0 @@
export * from './codemods';
export * from './frameworks';

View File

@ -11,6 +11,4 @@ export * from './types';
export * from './storybook-channel-mock';
export * from './hooks';
export * from './postinstall';
export default addons;

View File

@ -90,31 +90,39 @@ export const addStorybookAddonToFile = (addonName, addonsFile, isOfficialAddon)
];
};
const LEGACY_CONFIGS = ['addons', 'config', 'presets'];
const postinstallAddon = async (addonName, isOfficialAddon) => {
let skipMsg = null;
if (!isOfficialAddon) {
skipMsg = 'unofficial addon';
} else if (!fs.existsSync('.storybook')) {
skipMsg = 'no .storybook config';
} else {
const presetsCodemod = require.resolve(
`${getPackageName(addonName, isOfficialAddon)}/postinstall/presets.js`
);
if (fs.existsSync(presetsCodemod)) {
if (fs.existsSync('.storybook')) {
skipMsg = 'no codmods found';
LEGACY_CONFIGS.forEach(config => {
try {
const codemod = require.resolve(
`${getPackageName(addonName, isOfficialAddon)}/postinstall/${config}.js`
);
commandLog(`Running postinstall script for ${addonName}`)();
const presetsFile = path.join('.storybook', 'presets.js');
if (!fs.existsSync(presetsFile)) {
fs.writeFileSync(presetsFile, '', 'utf8');
let configFile = path.join('.storybook', `${config}.ts`);
if (!fs.existsSync(configFile)) {
configFile = path.join('.storybook', `${config}.js`);
if (!fs.existsSync(configFile)) {
fs.writeFileSync(configFile, '', 'utf8');
}
}
spawnSync('npx', ['jscodeshift', '-t', presetsCodemod, presetsFile], {
spawnSync('npx', ['jscodeshift', '-t', codemod, configFile], {
stdio: 'inherit',
});
} else {
skipMsg = 'no .storybook config';
skipMsg = null;
} catch (err) {
// resolve failed, skip
}
} else {
skipMsg = `no codemod: ${presetsCodemod}`;
}
});
}
if (skipMsg) {
commandLog(`Skipping postinstall for ${addonName}, ${skipMsg}`)();
}
@ -134,7 +142,7 @@ export default async function add(addonName, options) {
}
}
addonCheckDone();
installAddon(addonName, npmOptions, isOfficialAddon);
// installAddon(addonName, npmOptions, isOfficialAddon);
if (!options.skipPostinstall) {
await postinstallAddon(addonName, isOfficialAddon);
}

20
lib/postinstall/README.md Normal file
View File

@ -0,0 +1,20 @@
# Storybook Postinstall Utilties
A minimal utility library for addons to update project configurations after the addon is installed via the [Storybook CLI](https://github.com/storybookjs/storybook/tree/master/lib/cli), e.g. `sb add docs`.
Each postinstall is written as a [jscodeshift](https://github.com/facebook/jscodeshift) codemod, with the naming convention `addon-name/postinstall/<file>.js` where `file` is one of { `config`, `addons`, `presets` }.
If these files are present in the addon, the CLI will run them on the existing file in the user's project (or create a new empty file if one doesn't exist). This library exists to make it really easy to make common modifications without having to muck with jscodeshift internals.
## Adding a preset
To add a preset to `presets.js`, simply create a file `postinstall/presets.js` in your addon:
```js
improt { presetsAddPreset } = require('@storybook/postinstall');
export default function transformer(file, api) {
const root = api.jscodeshift(file.source);
presetsAddPreset(`@storybook/addon-docs/preset`, { some: 'options' }, { root, api });
return root.toSource();
};
```

View File

@ -0,0 +1,39 @@
{
"name": "@storybook/postinstall",
"version": "5.3.0-alpha.42",
"description": "",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybookjs/storybook/tree/master/lib/postinstall",
"bugs": {
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybookjs/storybook.git",
"directory": "lib/postinstall"
},
"license": "MIT",
"files": [
"dist/**/*",
"README.md",
"*.js",
"*.d.ts"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"core-js": "^3.0.1"
},
"devDependencies": {
"@hypnosphi/jscodeshift": "^0.6.4",
"jest-specific-snapshot": "^2.0.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -6,3 +6,10 @@ exports[`add-preset-options transforms correctly using "basic.input.js" data 1`]
options: {\\"a\\":[1,2,3],\\"b\\":{\\"foo\\":\\"bar\\"},\\"c\\":\\"baz\\"}
}];"
`;
exports[`presets-add-preset-options transforms correctly using "basic.input.js" data 1`] = `
"module.exports = ['foo', {
name: \\"test\\",
options: {\\"a\\":[1,2,3],\\"b\\":{\\"foo\\":\\"bar\\"},\\"c\\":\\"baz\\"}
}];"
`;

View File

@ -6,3 +6,10 @@ exports[`add-preset-options transforms correctly using "empty.input.js" data 1`]
options: {\\"a\\":[1,2,3],\\"b\\":{\\"foo\\":\\"bar\\"},\\"c\\":\\"baz\\"}
}];"
`;
exports[`presets-add-preset-options transforms correctly using "empty.input.js" data 1`] = `
"module.exports = [{
name: \\"test\\",
options: {\\"a\\":[1,2,3],\\"b\\":{\\"foo\\":\\"bar\\"},\\"c\\":\\"baz\\"}
}];"
`;

View File

@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`add-preset transforms correctly using "basic.input.js" data 1`] = `"module.exports = ['foo', \\"test\\"];"`;
exports[`presets-add-preset transforms correctly using "basic.input.js" data 1`] = `"module.exports = ['foo', \\"test\\"];"`;

View File

@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`add-preset transforms correctly using "empty.input.js" data 1`] = `"module.exports = [\\"test\\"];"`;
exports[`presets-add-preset transforms correctly using "empty.input.js" data 1`] = `"module.exports = [\\"test\\"];"`;

View File

@ -1,4 +1,4 @@
import { addPreset } from '../codemods';
import { addPreset } from '../presets';
export default function transformer(file, api) {
const j = api.jscodeshift;

View File

@ -1,4 +1,4 @@
import { addPreset } from '../codemods';
import { addPreset } from '../presets';
export default function transformer(file, api) {
const j = api.jscodeshift;

View File

@ -0,0 +1,2 @@
export { addPreset as presetsAddPreset } from './presets';
export * from './frameworks';

View File

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["src/**.test.ts"]
}