-
Notifications
You must be signed in to change notification settings - Fork 165
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
storybook, npm, webpack setup - draft (#184)
* draft * Updated docs with feedback
- Loading branch information
Showing
2 changed files
with
209 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
# Bundling with Webpack for NPM and Storybook | ||
|
||
_Based on PR [#135](https://github.com/bbc/react-transcript-editor/pull/135)_ | ||
|
||
> [Storybook](https://storybook.js.org/) is an open source tool for developing UI components in isolation for React, Vue, and Angular. It makes building stunning UIs organized and efficient. | ||
## Getting from Code change to Storybook | ||
|
||
1. Commit changes to master | ||
2. Publish component to NPM | ||
1. `npm run publish:public` | ||
3. Publish to Github Pages - `npm run deploy:ghpages` | ||
|
||
## Webpack | ||
|
||
Webpack is used for bundling the component for NPM distribution. We followed [this guide](http://jasonwatmore.com/post/2018/04/14/react-npm-how-to-publish-a-react-component-to-npm) and [webpack docs](https://webpack.js.org/concepts) in order to publish React Component to NPM. | ||
|
||
When we run `npm run publish:public` to publish components to NPM, it also runs `pre:publish`, which also runs `build:component`, which generates a `webpack.config.js`. | ||
|
||
```js | ||
const path = require("path"); | ||
|
||
module.exports = { | ||
mode: "production", | ||
devtool: "source-map", | ||
entry: { | ||
index: "./packages/index.js", | ||
TranscriptEditor: "./packages/components/transcript-editor/index.js", | ||
TimedTextEditor: "./packages/components/timed-text-editor/index.js", | ||
MediaPlayer: "./packages/components/media-player/index.js", | ||
ProgressBar: "./packages/components/media-player/src/ProgressBar.js", | ||
PlaybackRate: "./packages/components/media-player/src/PlaybackRate.js", | ||
PlayerControls: | ||
"./packages/components/media-player/src/PlayerControls/index.js", | ||
RollBack: "./packages/components/media-player/src/RollBack.js", | ||
Select: "./packages/components/media-player/src/Select.js", | ||
VideoPlayer: "./packages/components/video-player/index.js", | ||
Settings: "./packages/components/settings/index.js", | ||
KeyboardShortcuts: "./packages/components/keyboard-shortcuts/index.js", | ||
timecodeConverter: "./packages/util/timecode-converter/index.js", | ||
exportAdapter: "./packages/export-adapters/index.js", | ||
sttJsonAdapter: "./packages/stt-adapters/index.js", | ||
groupWordsInParagraphsBySpeakersDPE: | ||
"./packages/stt-adapters/digital-paper-edit/group-words-by-speakers.js" | ||
}, | ||
output: { | ||
path: path.resolve("dist"), | ||
filename: "[name].js", | ||
libraryTarget: "commonjs2" | ||
}, | ||
optimization: { | ||
minimize: true | ||
}, | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.module.css$/, | ||
use: [ | ||
{ | ||
loader: "style-loader" | ||
}, | ||
{ | ||
loader: "css-loader", | ||
options: { | ||
modules: true | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
test: /\.(js|jsx)$/, | ||
include: path.resolve(__dirname, "packages"), | ||
// TODO: because it uses entry point to determine graph of dependencies, might not be needed to exclude test ans sample files? | ||
exclude: /(node_modules|bower_components|build|dist|demo|.storybook)/, | ||
use: { | ||
loader: "babel-loader", | ||
options: { | ||
presets: ["@babel/preset-env", "@babel/preset-react"] | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
resolve: { | ||
alias: { | ||
react: path.resolve(__dirname, "./node_modules/react"), | ||
"react-dom": path.resolve(__dirname, "./node_modules/react-dom") | ||
} | ||
}, | ||
externals: { | ||
react: { | ||
commonjs: "react", | ||
commonjs2: "react", | ||
amd: "React", | ||
root: "React" | ||
}, | ||
"react-dom": { | ||
commonjs: "react-dom", | ||
commonjs2: "react-dom", | ||
amd: "ReactDOM", | ||
root: "ReactDOM" | ||
} | ||
} | ||
}; | ||
``` | ||
|
||
[Webpack also works out the dependency tree from the entry points](https://webpack.js.org/concepts/#entry) as it's making it's own [dependency graph](https://webpack.js.org/concepts/dependency-graph/). Since it's using production, the bundling process will automatically exclude test and sample files. | ||
|
||
### Importing Components | ||
|
||
Using [Webpack code splitting entry points](https://webpack.js.org/guides/code-splitting/#entry-points) as well as exporting from `packages/index.js`, you can now do both styles of importing: | ||
|
||
```js | ||
import TimedTextEditor from "@bbc/react-transcript-editor/TimedTextEditor"; | ||
``` | ||
|
||
and | ||
|
||
```js | ||
import { TimedTextEditor } from "@bbc/react-transcript-editor"; | ||
``` | ||
|
||
However, as mentioned in the README - __it is preferred to import individual components like using the first option: | ||
`@bbc/react-transcript-editor/TimedTextEditor`__ as the other importing method imports the entire library. | ||
|
||
### Caveats | ||
|
||
#### Size limit | ||
|
||
At the moment webpack complains that some files are above the recommended size limit. It would be interesting to see if there's a way to reduce this with some further optimization with lazy-loading or other ways. But this is for a subsequent PR for now. | ||
|
||
```t | ||
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). | ||
This can impact web performance. | ||
Assets: | ||
TimedTextEditor.js (271 KiB) | ||
TranscriptEditor.js (455 KiB) | ||
index.js (455 KiB) | ||
``` | ||
|
||
#### CSS module support for Storybook | ||
|
||
Storybooks __DO NOT support CSS modules out of the box__, so if you remove CRA (`create-react-app`) scripts [the css modules will not load in the Storybook](https://github.com/storybooks/storybook/issues/2320). | ||
`storybook/webpack.config.js` augments the storybook with support for CSS modules. | ||
|
||
## Testing | ||
|
||
To run `Jest` across the react components, we have to stub the css file dependencies using [`moduleNameMapper`](https://jestjs.io/docs/en/configuration#modulenamemapper-object-string-string) under the jest attribute in `package.json` | ||
|
||
### Further reading | ||
|
||
#### References | ||
|
||
- [How to package your React Component for distribution via NPM](https://itnext.io/how-to-package-your-react-component-for-distribution-via-npm-d32d4bf71b4f) | ||
|
||
#### Previous setups | ||
|
||
- [Component Development Set up (old)](https://github.com/bbc/react-transcript-editor/blob/master/docs/adr/2018-10-05-component-development-setup.md) | ||
- [Babel Setup](https://github.com/bbc/react-transcript-editor/blob/master/docs/adr/2018-10-05-component-development-setup.md) to do the build. | ||
|
||
```diff | ||
- "build:component": "rimraf dist && NODE_ENV=production babel packages/ --out-dir dist --copy-files && rimraf dist/**/*.sample.json dist/**/*.sample.js dist/**/example-usage.js dist/**/*.test.js dist/**/*__tests__ dist/**/*__snapshots__ dist/**/*.spec.js", | ||
+ "build:component": "webpack --config webpack.config.js", | ||
+"pre:publish": "npm run build:component && rm ./dist/package.json || true && cp package.json ./dist/package.json && rm ./dist/README.md || true && cp README.md ./dist/README.md || true ", | ||
+"publish:public": "npm run pre:publish && npm publish dist --access public", | ||
``` |