1.我们首先看看下面的代码
'use strict';
const chain = require('ramda/src/chain');
const toReactComponent = require('jsonml-to-react-component');
//jsonml-to-react-component
const exist = require('exist.js');
const NotFound = require('{{ themePath }}/template/NotFound');
//replace dynamic param with truely passed param value
function calcPropsPath(dataPath,params) {
return Object.keys(params).reduce(
(path,param) => path.replace(`:${param}`,params[param]),dataPath
);
}
//Some dynamic parameter injected
function hasParams(dataPath) {
return dataPath.split('/').some((snippet) => snippet.startsWith(':'));
}
//Do nothing
function defaultCollect(nextProps,callback) {
callback(null,nextProps);
}
/* We receive something like this: var Promise = require('bluebird'); module.exports = { markdown: { 'posts\demo2': require('C:/Users/Administrator/Desktop/mdw/posts/demo2.md'),'posts\demos\demo1': require('C:/Users/Administrator/Desktop/mdw/posts/demos/demo1.md'),},plugins: [ ],picked: {},}; */
module.exports = function getRoutes(data) {
const plugins = data.plugins;
//All 'browser' module
const converters = chain((plugin) => plugin.converters || [],plugins);
//converters is for jsonml converter in `browser` mode
const utils = {
get: exist.get,toReactComponent(jsonml) {
return toReactComponent(jsonml,converters);
},};
//utils`s method toReactComponent is for converting jsonml to react component
plugins.map((plugin) => plugin.utils || {})
.forEach((u) => Object.assign(utils,u));
//plugins`s personal util function is also assiged to final utils object
//@template is path of component while dataPath is `path` parameter
function templateWrapper(template,dataPath = '') {
//template is ususally ./template/NotFound
const Template = require('{{ themePath }}/template' + template.replace(/^\.\/template/,''));
//We get final path of component
return (nextState,callback) => {
const propsPath = calcPropsPath(dataPath,nextState.params);
//replace dynamic parameter of url,such as `path: 'docs/pattern/:children'`
const pageData = exist.get(data.markdown,propsPath.replace(/^\//,'').split('/'));
//Urls are mapped to component instantiation
const collect = Template.collect || defaultCollect;
//We firstly invoke our template`s collect function,passed value are combined with nextState
//and prevIoUs object with data,picked,pageData,utils contained
collect(Object.assign({},nextState,{
data: data.markdown,picked: data.picked,//page data is for special html page based on url
utils,}),(err,nextProps) => {
const Comp = (hasParams(dataPath) || pageData) && err !== 404 ?
Template.default || Template : NotFound.default || NotFound;
//ES6 based component,we need to import .default while module.exports do not need to
const dynamicPropsKey = nextState.location.pathname;
//we get pathname
Comp[dynamicPropsKey] = nextProps;
//In create-element.js,we do that. <Component {...props} {...Component[dynamicPropsKey]} />
//something as bellow
/* <ReactRouter.Router history={ReactRouter.useRouterHistory(history.createHistory)({ basename })} routes={routes} createElement={createElement}//that is createElement Function />; module.exports = function createElement(Component,props) { const dynamicPropsKey = props.location.pathname; return <Component {...props} {...Component[dynamicPropsKey]} />; }; */
callback(err === 404 ? null : err,Comp);
//https://react-guide.github.io/react-router-cn/docs/guides/advanced/DynamicRouting.html
//callback of react-router natively
});
};
}
const theme = require('{{ themePath }}');
// We get index file from themePath which is configured as core part of react-router
const routes = Array.isArray(theme.routes) ? theme.routes : [theme.routes];
//Get router part of react-router,routes part ususally configured as follows:
/* routes: { path: '/',component: './template/Layout/index',indexRoute: { component: homeTmpl },childRoutes: [{ path: 'index-cn',component: homeTmpl,}],*/
function processRoutes(route) {
if (Array.isArray(route)) {
//map is used to manipulate some object
return route.map(processRoutes);
}
return Object.assign({},route,{
onEnter: () => {
if (typeof document !== 'undefined') {
}
},component: undefined,//Same as component but asynchronous,useful for code-splitting.
//https://github.com/liangklfang/react-router/blob/master/docs/API.md#getcomponentsnextstate-callback
//http://www.mtons.com/content/61.htm
getComponent: templateWrapper(route.component,route.dataPath || route.path),//Get component file path and 'path' for url
indexRoute: route.indexRoute && Object.assign({},route.indexRoute,{
component: undefined,getComponent: templateWrapper(
route.indexRoute.component,route.indexRoute.dataPath || route.indexRoute.path
),childRoutes: route.childRoutes && route.childRoutes.map(processRoutes),});
}
const processedRoutes = processRoutes(routes);
//Here,We process Routes configuration
processedRoutes.push({
path: '*',getComponents: templateWrapper('./template/NotFound'),});
//Here is default router!
return processedRoutes;
};
2.可以学到的内容
2.1 动态加载的方法getComponents,getIndexRoute,getChildRoutes等,可以参考react-router
function processRoutes(route) {
if (Array.isArray(route)) {
//map is used to manipulate some object
return route.map(processRoutes);
}
return Object.assign({},});
}
2.2 传入默认的路由方式
processedRoutes.push({
path: '*',});
2.3 react-router的createElement配置
ReactRouter.match({ routes,location,basename },() => {
const router =
<ReactRouter.Router @H_403_286@history={ReactRouter.useRouterHistory(history.createHistory)({ @H_403_286@basename })} @H_403_286@routes={routes} @H_403_286@createElement={createElement} />;
ReactDOM.render(
router,document.getElementById('react-content')
);
});
其中这里我们采用的是下面的函数,这个函数指定了当访问一个url的时候如何为我们的Component组件添加props:
module.exports = function createElement(Component,props) {
const dynamicPropsKey = props.location.pathname;
return <Component {@H_403_286@...props} {@H_403_286@...Component[@H_403_286@dynamicPropsKey]} />;
};
之所以我们这样做是上面通过了Component[dynamicPropsKey]传入了需要的props
const Comp = (hasParams(dataPath) || pageData) && err !== 404 ?
Template.default || Template : NotFound.default || NotFound;
//ES6 based component,we need to import .default while module.exports do not need to
const dynamicPropsKey = nextState.location.pathname;
//we get pathname
Comp[dynamicPropsKey] = nextProps;
2.4 React中ES6模式导出要通过.default完成,而Commonjs规范不需要
const Comp = (hasParams(dataPath) || pageData) && err !== 404 ?
Template.default || Template : NotFound.default || NotFound;
2.5 URL映射到组件实例化
function templateWrapper(template,Comp);
//https://react-guide.github.io/react-router-cn/docs/guides/advanced/DynamicRouting.html
//callback of react-router natively
});
};
}