Build system that creates interactive component previews using Parcel bundler with support for React and Vue components.
Creates entry files and bundles components for live preview functionality.
/**
* Bundles React/Vue components for live preview
* @param {ComponentInfo[]} Components - Array of component information to bundle
* @param {string} out - Output directory for generated files
* @param {Object} config - Build configuration including better-docs settings
*/
function bundle(Components: ComponentInfo[], out: string, config: Object): void;
interface ComponentInfo {
component: {
/** Component display name */
displayName: string;
/** Path to component source file */
filePath: string;
/** Component type (react or vue) */
type: 'react' | 'vue';
};
}
interface BundleConfig {
betterDocs?: {
component?: {
/** Path to custom wrapper component */
wrapper?: string;
/** Additional entry file commands */
entry?: string[];
};
};
}Generates entry files that import and register all documented components:
/**
* Generated entry file structure that imports components and sets up the preview environment
*/
interface GeneratedEntry {
/** Global component registrations */
globals: {
reactComponents: Object;
vueComponents: Object;
Vue?: Object;
React?: Object;
ReactDOM?: Object;
VueWrapper?: Object;
ReactWrapper?: Object;
};
/** Component imports and registrations */
componentImports: string[];
/** CSS imports for styling */
cssImports: string[];
/** Custom wrapper imports */
customImports?: string[];
}For React components, the bundler creates an entry file that:
import React from "react";
import ReactDOM from "react-dom";
window.React = React;
window.ReactDOM = ReactDOM;import ReactWrapper from './lib/react-wrapper.js';
window.ReactWrapper = ReactWrapper;import Component0 from './src/Button.jsx';
import Component1 from './src/Modal.jsx';
reactComponents['Button'] = Component0;
reactComponents['Modal'] = Component1;For Vue components, the bundler creates an entry file that:
import Vue from 'vue/dist/vue.js';
window.Vue = Vue;import VueWrapper from './lib/vue-wrapper.js';
window.VueWrapper = VueWrapper;import Component0 from './src/Card.vue';
import Component1 from './src/ProgressBar.vue';
vueComponents['Card'] = Component0;
vueComponents['ProgressBar'] = Component1;The bundler supports projects with both React and Vue components:
// Generated entry file for mixed projects
window.reactComponents = {};
window.vueComponents = {};
// React setup
import React from "react";
import ReactDOM from "react-dom";
import ReactWrapper from './lib/react-wrapper.js';
window.React = React;
window.ReactDOM = ReactDOM;
window.ReactWrapper = ReactWrapper;
// Vue setup
import Vue from 'vue/dist/vue.js';
import VueWrapper from './lib/vue-wrapper.js';
window.Vue = Vue;
window.VueWrapper = VueWrapper;
// Component imports
import ReactButton from './src/Button.jsx';
import VueCard from './src/Card.vue';
reactComponents['Button'] = ReactButton;
vueComponents['Card'] = VueCard;The bundler automatically includes required CSS files:
// Default CSS imports
import './styles/reset.css';
import './styles/iframe.css';
// Additional CSS can be added via configuration
import 'bulma/css/bulma.css';
import './custom-styles.css';When a custom wrapper is specified, it's imported and made available globally:
import _CustomWrapper from './path/to/custom-wrapper.js';
window._CustomWrapper = _CustomWrapper;Enable component bundling with minimal configuration:
{
"plugins": [
"node_modules/better-docs/component"
]
}Specify a custom wrapper component for providing context:
{
"templates": {
"better-docs": {
"component": {
"wrapper": "./src/docs/ComponentWrapper.js"
}
}
}
}Custom Wrapper Example:
// ComponentWrapper.js
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
import theme from '../theme';
const ComponentWrapper = ({ children }) => {
return (
<ThemeProvider theme={theme}>
<BrowserRouter>
<div className="component-preview">
{children}
</div>
</BrowserRouter>
</ThemeProvider>
);
};
export default ComponentWrapper;Add custom imports and setup code to the entry file:
{
"templates": {
"better-docs": {
"component": {
"entry": [
"import 'babel-polyfill';",
"import 'normalize.css';",
"import './src/styles/global.css';",
"console.log('Component preview initialized');"
]
}
}
}
}Complete configuration with all options:
{
"plugins": [
"node_modules/better-docs/component"
],
"templates": {
"better-docs": {
"component": {
"wrapper": "./docs/ComponentWrapper.js",
"entry": [
"import 'babel-polyfill';",
"import 'bulma/css/bulma.css';",
"import './src/styles/docs.css';",
"window.DOCS_MODE = true;"
]
}
}
}
}The bundling process creates the following files in the output directory:
docs/
├── entry.js # Generated entry file
├── build/ # Parcel build output
│ ├── entry.js # Bundled JavaScript
│ ├── entry.css # Bundled CSS
│ └── assets/ # Bundled assets
├── styles/
│ ├── reset.css # Reset styles
│ └── iframe.css # Iframe-specific styles
└── [documentation files]The bundler generates and executes a Parcel command:
NODE_ENV=development parcel build entry.js --dist-dir buildThe bundler handles path differences across platforms:
/**
* Converts file paths for cross-platform compatibility
* @param {string} path - File path to convert
* @returns {string} Cross-platform compatible path
*/
function pathCrossEnv(path: string): string;The bundler includes comprehensive error handling:
try {
execSync(cmd);
console.log('Bundling completed successfully');
} catch (error) {
if (error.output && error.output.length) {
console.log(error.output[1].toString());
}
throw error;
}The component bundling system requires:
# Install parcel globally
npm install -g parcel-bundler
# Install better-docs with component support
npm install --save-dev better-docs
# For React projects
npm install react react-dom
# For Vue projects
npm install vue@component tag is presentEnable verbose output for debugging:
{
"opts": {
"verbose": true
}
}