We're doing this at nerd wallet in a crude way in order to dynamically build a page of react component examples.
Would be great to start factoring out some of the logic involved with this in to individual modules. I want to start at the component parsing level and just make that clean.
Given a component module structure like this:
button
- index.jsx (or button.jsx)
- index.css (or less or sass or whatevs)
- /examples
- button-sizes.jsx
- button-variants.jsx
- package.json
Produce an object of file refs and meta data like:
require('parse-component/component')
{
name: 'button', // parsed from package.json
pkg: {
version: '1.0.0', // key fields from package.json, but not the whole thing?
...
},
path: 'node_modules/button'
}
Then we could parse examples for the component to get an array of these objects:
require('parse-component/examples')
{
key: 'button-variants',
name: 'Button Variants', // do some simple manipulation of the key
path: 'node_modules/button/examples/button-variants.jsx',
component: 'button'
}
Trying to keep component and examples object small. Adding package.json data would be cool because then we can render things like contributor avatars next to the component… Easy to see who the owners/experts are for a given component… Things like that.
The hard part is rendering the example source, rendering the example and bundling any JS logic (like clicking a button could trigger an alert). We did this in our react-components project, but it slows the build time down (we render the guide as a static site). I have a branch using streams instead of async file reading to keep memory down as example/component source can get big for a large component library. Currently I attach a stream object to an example or component that is just a read stream of the source and a ref object which is the actual component code from require('button') in this case so I can render the example.
Wondering if it's best to make the ref/streaming stuff utilities (separate modules) from this module that takes example and component objects return ref/streaming for actual build time…
var parseExamples = require('parse-component/examples')
var readExample = require('read-component-example')
parseExamples('path/to/component', function (err, examples) {
if (err) return console.error(err)
// would iterate over all examples, but simple to explain one
readExample(examples[0], function (err, exampleRefs) {
// executes example code that you could pipe (string-to-stream)
// to the guide
var html = exampleRefs.ref()
// pipe the example source code for rendering in to the guide
exampleRefs.stream.pipe(guideStream)
// Use something like browserify to get a bundle for executing
// the example clientside.
// Could optimize this by rendering one bundle for all examples per
// component. Need a way of passing in the example container element for
// correct scoping.
var bundleSrc = 'var example = require(' + examples[0].path + ')' +
'React.render(example, '#example-' + examples[0].key)'
var b = require('browserify')({ entries: [bundleSrc] })
b.bundle().pipe(destBundle)
})
})
Note that a lot of this code is just sketching out concepts… probably tons of errors and definitely won't execute as is.
We're doing this at nerd wallet in a crude way in order to dynamically build a page of react component examples.
Would be great to start factoring out some of the logic involved with this in to individual modules. I want to start at the component parsing level and just make that clean.
Given a component module structure like this:
Produce an object of file refs and meta data like:
require('parse-component/component')
Then we could parse examples for the component to get an array of these objects:
require('parse-component/examples')
Trying to keep
component
andexamples
object small. Adding package.json data would be cool because then we can render things like contributor avatars next to the component… Easy to see who the owners/experts are for a given component… Things like that.The hard part is rendering the example source, rendering the example and bundling any JS logic (like clicking a button could trigger an
alert
). We did this in our react-components project, but it slows the build time down (we render the guide as a static site). I have a branch using streams instead of async file reading to keep memory down as example/component source can get big for a large component library. Currently I attach astream
object to an example or component that is just a read stream of the source and aref
object which is the actual component code fromrequire('button')
in this case so I can render the example.Wondering if it's best to make the ref/streaming stuff utilities (separate modules) from this module that takes example and component objects return ref/streaming for actual build time…
Note that a lot of this code is just sketching out concepts… probably tons of errors and definitely won't execute as is.