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

storybook, npm, webpack setup - draft #184

Merged
merged 2 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 43 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ _--> Work in progress <--_

<!-- _Screenshot of UI - optional_ -->

- [You can see a demo by clicking here ](https://bbc.github.io/react-transcript-editor/iframe.html?id=demo--default) (and then click the `load demo` button)
- [You can see a demo by clicking here](https://bbc.github.io/react-transcript-editor/iframe.html?id=demo--default) (and then click the `load demo` button)
- [And you can see a list of features here](./docs/features-list.md).

## Development env
Expand Down Expand Up @@ -56,35 +56,33 @@ npm install @bbc/react-transcript-editor
```

```js
import TranscriptEditor from '@bbc/react-transcript-editor';
import TranscriptEditor from "@bbc/react-transcript-editor";
```

```js
<TranscriptEditor
transcriptData={ someJsonFile }
mediaUrl={'https://download.ted.com/talks/KateDarling_2018S-950k.mp4'}
isEditable={true}
spellCheck={false}
sttJsonType={ 'bbckaldi' }
handleAnalyticsEvents={ this.handleAnalyticsEvents }
fileName={'ted-talk.mp4'}
title={'Ted Talk'}
ref={ this.transcriptEditorRef }
/>
<TranscriptEditor
transcriptData={someJsonFile}
mediaUrl={"https://download.ted.com/talks/KateDarling_2018S-950k.mp4"}
isEditable={true}
spellCheck={false}
sttJsonType={"bbckaldi"}
handleAnalyticsEvents={this.handleAnalyticsEvents}
fileName={"ted-talk.mp4"}
title={"Ted Talk"}
ref={this.transcriptEditorRef}
/>
```


| Attributes | Description | required | type |
| :------------- | :---------- | :-----------: | :-----------: |
| transcriptData | Transcript json | yes | Json |
| mediaUrl | string url to media file - audio or video | yes | String |
| isEditable | set to true if you want to be able to edit the text | no | Boolean |
|spellCheck | set to true if you want the browser to spell check this transcript | no | Boolean |
| handleAnalyticsEvents | if you want to collect analytics events. | no | Function |
| fileName |used for saving and retrieving local storage blob files | no | String |
| title | defaults to empty string | no | String |
| ref | if you want to have access to internal functions such as retrieving content from the editor. eg to save to a server/db.| no | React ref |

| Attributes | Description | required | type |
| :-------------------- | :---------------------------------------------------------------------------------------------------------------------- | :------: | :-------: |
| transcriptData | Transcript json | yes | Json |
| mediaUrl | string url to media file - audio or video | yes | String |
| isEditable | set to true if you want to be able to edit the text | no | Boolean |
| spellCheck | set to true if you want the browser to spell check this transcript | no | Boolean |
| handleAnalyticsEvents | if you want to collect analytics events. | no | Function |
| fileName | used for saving and retrieving local storage blob files | no | String |
| title | defaults to empty string | no | String |
| ref | if you want to have access to internal functions such as retrieving content from the editor. eg to save to a server/db. | no | React ref |

See [`./demo/app.js` demo](./demo/app.js) as a more detailed example usage of the component.

Expand Down Expand Up @@ -119,10 +117,11 @@ You can also import some of the underlying React components directly.
To import the components you can do as follows

```js
import TimedTextEditor from '@bbc/react-transcript-editor/TimedTextEditor';
import TimedTextEditor from "@bbc/react-transcript-editor/TimedTextEditor";
```

```js
import { TimedTextEditor } from '@bbc/react-transcript-editor';
import { TimedTextEditor } from "@bbc/react-transcript-editor";
```

However if you are not using `TranscriptEditor` it is recommended to follow the second option and import individual components like: `@bbc/react-transcript-editor/TimedTextEditor` rather than the entire library. Doing so pulls in only the specific components that you use, which can significantly reduce the amount of code you end up sending to the client. (Similarly to how [`react-bootstrap`](https://react-bootstrap.github.io/getting-started/introduction) works)
Expand All @@ -132,23 +131,31 @@ See [the storybook](https://bbc.github.io/react-transcript-editor) for each comp
You can also use this node modules as standalone

```js
import exportAdapter from '@bbc/react-transcript-editor/exportAdapter'
import exportAdapter from "@bbc/react-transcript-editor/exportAdapter";
```

Converts from draftJs json format to other formats

```js
import sttJsonAdapter from '@bbc/react-transcript-editor/sttJsonAdapter'
import sttJsonAdapter from "@bbc/react-transcript-editor/sttJsonAdapter";
```

Converts various stt json formats to draftJs

```js
import { secondsToTimecode, timecodeToSeconds, shortTimecode} from '@bbc/react-transcript-editor/timecodeConverter'
import {
secondsToTimecode,
timecodeToSeconds,
shortTimecode
} from "@bbc/react-transcript-editor/timecodeConverter";
```

some modules to convert to and from timecodes

## System Architecture

<!-- _High level overview of system architecture_ -->

- uses [`storybook`](https://storybook.js.org) with the setup as [explained in their docs](https://storybook.js.org/docs/guides/guide-react/) to develop this React.
- This uses [CSS Modules](https://github.com/css-modules/css-modules) to contain the scope of the css for this component.
- [`.storybook/webpack.config.js](./.storybook/webpack.config.js) enanches the storybook webpack config to add support for css modules.
Expand Down Expand Up @@ -187,14 +194,13 @@ npm run build:component

- **Demo** can be viewed at [https://bbc.github.io/react-transcript-editor/iframe.html?id=demo--default](https://bbc.github.io/react-transcript-editor/iframe.html?id=demo--default)


http://localhost:6006


<!-- https://github.com/gitname/react-gh-pages
-->

## Build - storybook

To build the storybook as a static site

```
Expand Down Expand Up @@ -226,17 +232,18 @@ npm run build:storybook:serve
```

## Tests

<!-- _How to carry out tests_ -->

Test coverage using [`jest`](https://jestjs.io/), to run tests

```
```sh
npm run test
```

During development you can use

```
```sh
npm run test:watch
```

Expand All @@ -263,7 +270,9 @@ This runs `npm run build:component` and `npm publish --access public` under the
See [CONTRIBUTING.md](./CONTRIBUTING.md) guidelines and [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) guidelines.

## Licence

<!-- mention MIT Licence -->

See [LICENCE](./LICENCE.md)

## Legal Disclaimer
Expand Down
166 changes: 166 additions & 0 deletions docs/guides/storybook-npm-setup.md
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",
```