The following sample code, which may contain multiple file code, is a bit messy. Umi/AF-Webpack was used for scaffolding construction and Vuant-UI was used for document layout style.
Thoughts together
- Implement a generic scaffolding, complete initialization of the project, build, and publish component documentation.
- Webpack was used to build the scaffolding because the documentation site is really an application
- Components need to have preview function, so we can adopt MPA multi-entry packaging
- A configuration file is agreed, in which the header and sideBar of the main configuration document are configured. This part is also equivalent to configuring route
- Use require.context to load the md file in the user directory
Begin to implement
The scaffold
Initialize the
Basically, the CLI has a template built in, and you can choose to have multiple fixed templates, or you can dynamically generate a personalized initial template individually through the init phase with options, technical solution: Inquirer + EJS or Mustache
Sample code:
async function init() {
try {
const answers = await inquirer.prompt(questions);
const { projectName, platform, framework, attributes, bu, site } = answers;
const templateRoot = path.join(__dirname, './boilerplate');
const projectPath = path.join(cwd, projectName);
await fse.copySync(templateRoot, projectPath, {
filter: (file) = > {
const reg = /\.(tpl|ejs)$/ig;
if (reg.test(file)) {
return false;
}
return true; }});const code = fse.readFileSync(path.join(templateRoot, 'config.ejs'), {
encoding: 'utf8'});await fse.writeFileSync(
path.join(projectPath, 'config.js'),
ejs.render(
code,
{
projectName,
platform,
framework,
attributes,
bu,
site,
},
),
{
encoding: 'utf8',}); signale.success(chalk.cyan('Project created successfully! '));
signale.info(chalk.cyan('NPM run dev Let's get to work! ! 😝 '));
} catch(error) { signale.error(error); }}Copy the code
build
The scaffolding construction function uses Webpack. In order to achieve it quickly, the af-Webpack configuration scheme within UMI is directly adopted and twice encapsulated 👍. When the scaffolding construction command is executed, relevant parameters of the local configuration are transparently transmitted to AF-Webpack, basically with a green light.
- Configuring Multiple Entries
entry: {
'docs': [
webpackHotDevClientPath, // Open HMR
path.join(paths.absTmpDirPath, './docs/index.js')],'preview': [
webpackHotDevClientPath,
path.join(paths.absTmpDirPath, './preview/index.js'),],}Copy the code
- Markdown parsing
In order to use markdown as a component output, keep the normal markdown-loader function and customize the loader slightly, so that front-matter configuration information can be directly displayed on the page, as follows:
function transformToComponent(content, fm) {
const { attributes } = fm;
return `
import React, { Component, Fragment } from 'react';
export default class extends Component {
state = {
html: 'The ${escape(content)}',
attr: The ${JSON.stringify(attributes)},
}
render() {
const { html, attr } = this.state;
const { platform, framework, attributes } = attr;
return (
<Fragment>
{/*<section>
<blockquote>
<ul>
{platform && <li>Platform: {platform}</li>}
{framework && <li>Framework: {framework}</li>}
{attributes && <li>Attributes: {attributes}</li>}
</ul>
</blockquote>
</section>*/}
<section dangerouslySetInnerHTML={{ __html: unescape(html) }} />
</Fragment>
)
}
}
`;
}
Copy the code
release
todo…
Example of a convention configuration file:
module.exports = {
header: {
logo: {
image: 'https://www.baidu.com'.title: 'YufPress'.href: '# /'}},// siderBar is a route that is resolved to a child route of the react-router
sideBar: {
name: 'UI'.groups: [{groupName: 'Base components'.list: [{disabled: false.enablePreview: true.// Whether to enable preview
path: '/Alert'.// Path (that is, the path under the docs folder
title: 'Alert',},]}]},};Copy the code
Example code for build time processing is as follows:
// Collect files
const docsMap = {};
const req = require.context('@root/docs'.true, /\.md$/);
req.keys().forEach((key) = > {
docsMap[key] = req(key);
});
/ / generates the route
import { sideBar } from '@root/config';
const routes = []; // Run the react-router command to generate a route
sideBar.groups.forEach((group) = > {
group.list.forEach((page) = > {
addRoute(page);
});
});
// addRoute
function addRoute(page) {
const { path, title, disabled = false } = page;
if (path) {
// Compatible processing
const module =
componentMap[`.${path}/readme.md`] ||
componentMap[`.${path}/README.md`] ||
componentMap[`.${path}.md`) | | {};if(! disabled) { routes.push({component: module.default || None,
name: `${path}`.path: ` /${path}`, title, }); }}}Copy the code
By the same token, the preview component (. (j | t) sx?) This file is the same way
conclusion
I started thinking, why am I writing this? I don’t think there’s much to write about. The next article will be about how I implemented the plug-in mechanism on this basis.