Electronic-Stories: emit more powerful stories

Dmytro Shaforostov
3 min readDec 3, 2018

--

Divide and conquer — is the main approach to programming and basically to all complex tasks. Components abstraction perfectly implement it. Same as an idea of developing them in an isolated environment like react-styleguidist and storybook. Mock, or use real data, you can remove all unnecessary stuff from a scene and concentrate on creating a required component.

Although storybook almost become a standard for developing web apps it is not really clear how to develop components for electron-based applications.
It may work if you use just standard web functionality, but it not designed for work with Electron desktop-app features. Mainly because it using iframe, as described in storybook issue.

Electronic-Stories is an attempt of solving this issue. Basically, it is another electron app that provides electron environment while you developing your application.

After been installed and added to your npm scripts in “package.json” as “electronic-stories”: “electronic-stories”. Then run “npm run electronic-stories” command, which will open Electron instance and show you stories in separate process using “webview”.
You will require to serve a script that loads all your stories on 9001 port HTML with, for example:

// index.js
(r => r.keys().forEach(r))(
require.context(‘./story’, true, /\.tale\.jsx$/),
);
// some.story.js
/* global storiesOf */
import React from ‘react’;
storiesOf(‘Basic’)
.add(
‘First’,
() => (
<button type=”button”>First</button>
),
).add(
‘Second’,
() => (
<button type=”button”>Second</button>
),
);

Notice that for proper work HTML file served on port must have “root” element and have “index.js” script.

// index.tpl.js
<!DOCTYPE html>
<html>
<head>
<meta charset=”utf-8">
<title>Stories</title>
</head>
<body>
<div id=”root”></div>
<script type=”text/javascript” src=”/bundle.js”></script>
</body>
</html>

For example you can use webpack for serving stories:

// webpack.config.js
const path = require(‘path’);
module.exports = () => ({
target: ‘electron-renderer’,
mode: ‘development’,
devtool: ‘eval-source-map’,
entry: {
app: path.join(__dirname, ‘./index.js’),
},
output: {
path: path.resolve(__dirname, ‘dist’),
publicPath: ‘/’,
filename: ‘bundle.js’,
},
devServer: {
contentBase: path.resolve(__dirname, ‘dist’),
port: 9001,
compress: true,
headers: {
‘Access-Control-Allow-Origin’: ‘*’,
},
},
});

Electronic-Stories will get code, implant “storiesOf” function to global scope and render stories list for switching between stories and will render components from stories itself.

Main feature that made this possible is an execution of preload script for webview.
Just before your modules with stories is start execution preload place API for them into global scope.
Calling storiesOf you create a new collection of stories that will add to list that will be sent to render process.
Preload script also will listen to events for switching between stories and will call react-dom’s render for showing them.
For now, Electronic-Stories works only for react components.

Another great thing is that you can run chromium devtools specifically for webview to inspect and receive your “Never happens” messages into console.

Electronic-Stories provides great flexibility for developing components. Currently provides API with minimum features, so PR’s are welcome at GetHub Repo!

--

--