Different set of dependencies for storybook and production built

Viewed 1178

I'm working at an internal react component library, the library is also featured with a storybook to present all the different elements.

The problem is, when I want to use Storybook I need React to be part as my dependencies (or devDependencies)

But to build the package react doesn't have to appear in any of the dependencies, but only in the peerDependencies.

(Adding react to devDependencies or dependencies is gonna generate a "multiple react instances" error while using the component library - being, obviously, in the node_modules of the built)

I'm not sure if generating dynamically the package.json depending on the build script command I'm gonna use is the correct approach in this case, or if there's a better way around it.

This works with yarn storybook and yarn build-storybook but using my yarn build_pkg is causing multiple react instances.

{
  "name": "library",
  "version": "0.1.0",
  "description": "Component Library",
  "main": "lib/index.js",
  "license": "MIT",
  "module": "lib/index.js",
  "types": "lib/index.d.ts",
  "files": [
    "lib/**/*"
  ],
  "dependencies": {
    "@material-ui/core": "^4.11.4",
    ...
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "build_pkg": "rm -rf ./lib && tsc --project ./tsconfig.json",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "start-storybook -p 6006 -s public",
    "build-storybook": "build-storybook -s public",
    "storybook-docs": "start-storybook --docs --no-manager-cache"
  },
  "devDependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    ...
  },
  "peerDependencies": {
    "@material-ui/lab": "4.0.0-alpha.47",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    "typescript": "^4.1.2",
    "web-vitals": "^1.0.1"
  },
  "resolutions": {
    "babel-loader": "8.1.0"
  }
}

On the other hand this created a perfect built package but storybook is complaining for missing React..

{
  "name": "library",
  "version": "0.1.0",
  "description": "Component Library",
  "main": "lib/index.js",
  "license": "MIT",
  "module": "lib/index.js",
  "types": "lib/index.d.ts",
  "files": [
    "lib/**/*"
  ],
  "dependencies": {
    "@material-ui/core": "^4.11.4",
    ...
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "build_pkg": "rm -rf ./lib && tsc --project ./tsconfig.json",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "start-storybook -p 6006 -s public",
    "build-storybook": "build-storybook -s public",
    "storybook-docs": "start-storybook --docs --no-manager-cache"
  },
  "devDependencies": {
    ...
  },
  "peerDependencies": {
    "@material-ui/lab": "4.0.0-alpha.47",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    "typescript": "^4.1.2",
    "web-vitals": "^1.0.1"
  },
  "resolutions": {
    "babel-loader": "8.1.0"
  }
}

Note that in the fist case I already added react as a devDependencies (hoping that would not be a part of the package built - but with no luck)

1 Answers

So, that's what I came with so far, I'm pretty sure there might be cleaner solution..

I created 2 different package.json files package.sb.json package.pkg.json

and I created a node script to be ran before the two builds that swap them (and the index file - to export only components on built pkg)

The node script looks like this

const fs = require('fs');

const args = process.argv.slice(2);
const flag = args.indexOf('-env');
if (flag === -1 || !args[flag + 1] || !['sb', 'pkg'].includes(args[flag + 1])) {
  console.error('\x1b[41m\x1b[1m%s\x1b[0m', 'ERR! An -env flag is required to be "sb" or "pkg"!');
  return;
}

const env = args[flag + 1];
const pkg = require(`./package.${env}.json`);
const index = {};
index.sb = `
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

`;

index.pkg = `export * from './components';`;

fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2), 'utf8');
fs.writeFileSync('./src/index.tsx', index[env], 'utf8');

The scripts in the package.json look like:

"scripts": {
    ...
    "build_pkg": "rm -rf ./lib node_modules package-lock.json yarn.lock && node fixbuild.js -env pkg && yarn && tsc --project ./tsconfig.json",
    ...
    "build-storybook": "rm -rf node_modules package-lock.json yarn.lock && node fixbuild.js -env sb && yarn && build-storybook -s public",
  },

Any better approach suggestion would be much appreciated :)

Related