Open iansinnott opened 8 years ago
Update
Thinking out loud here. One possible approach is webpack contexts. For example, given a posts/
directory containing js files that export components to be rendered as blog posts we could do this:
// Import all necessary modules up here...
// Get a list of post components using webpack context
const context = require.context('./posts', false, /\.js$/);
const posts = context.keys().sort().map(context);
export const routes = (
<Route path='/' title='App' component={App}>
{/* Other router config here... */}
{posts.map((module, i) => {
const Component = module.__esModule ? module.default : module;
return <Route key={i} path={String(i)} component={Component} />;
})}
<Route path='*' title='404: Post Not Found' component={NotFound} />
</Route>
);
export default routes;
Another potential solution would be to expect directories to exist based on routes. For example, given the following router config:
// Import all necessary modules up here...
export const routes = (
<Route path='/' title='App' component={App}>
<Route path='posts' component={Posts}>
<IndexRoute component={PostList} />
<Route path=':id' component={Post} />
</Route>
<Route path='*' title='404: Post Not Found' component={NotFound} />
</Route>
);
export default routes;
We would see the :id
route and infer the that the user must have a directory on the filesystem containing the files necessary to generate these routes. In this case, we would look up the tree and see the parent route has a path of 'posts'
so we would expect a posts/
directory at the project root.
Drawbacks:
Post
component look like? How would the data necessary to build the component be passed in?Why not allow to pass path ([]) as option and then in https://github.com/iansinnott/react-static-webpack-plugin/blob/master/src/index.js#L83
merge the user one and the ones from the router.
That would remove any dependencies on file system or such and open it for other underlying logic to generate the paths.
---webpack.config.js
/*
* the variable could be generated from outside and then set dynamically.
* in my use case I fetch some json data (jenkins-plugins) and if that is fetched I want to invoke a static export of all the detail page of each plugin. So I would end up with an array of 1200+ and pass it to the plugin
*/
const paths = ['/', '/post/xxx', '...'];
new StaticSitePlugin({
paths: paths,
src: 'app',
stylesheet: '/app.css',
favicon: '/favicon.ico',
}),
--index.js#L83
const routerPaths = getAllPaths(Component);
log('Parsed routes:', routerPaths);
const { paths: userPaths } = this.options;
const paths = Array.from(new Set(routerPaths.concat(userPaths)));
Or are there some pitfalls that I do not see?
Hm, where would you get the paths
from?
I'm not entirely clear how this would work, but you might be on to something here. So let's assume you already had the array of paths, how would use use them in your routes.js
file?
If you put together or a complete example of how the API might look I'm happy to check it out. I would also welcome a pull request if you think you have a solution :)
@iansinnott the path you can inject or write them as I did in the above example. I will have a look now since I am may need to change how the plugin resolves the paths.
As short explanation I am ATM working on https://github.com/scherler/react-static-boilerplate/tree/redux the redux branch to add it to the boilerplate if you like it. However there is a problem in the way we normally would invoke the store vs. the export all routes.
If you look into the above branch you will find
<Provider store={store}>
<Router routes={routes} history={browserHistory} />
</Provider>
To inject the store you need to to this in the top parent or you will need to do it in each route. I am still playing around to see whether I can move it around somehow, will let you know.
@iansinnott Gatsby does this by traversing the file-tree. https://github.com/gatsbyjs/gatsby/blob/master/lib/isomorphic/create-routes.js
It uses https://github.com/markdalgleish/static-site-generator-webpack-plugin/ underneath which provides a routes
option. It does not use react-router
, so all the routes need to be specified by the user. If I am not wrong, @scherler was suggesting something along that line (merging user provided routes into the already existing ones from react-router
).
However, I like your require.context
approach. Any progress on that?
Hey @sidjain26 thanks for the ping. I haven't looked at this issue in a while, because for whatever reason I haven't yet run into the need for dynamic routes. I've been using this plugin extensively but it's all been for sites without dynamic routing.
In my own minimal testing in the past the context approach actually worked quite well. it's currently the option I favor because it is explicit and doesn't require the user to know any special configuration—this is a first class goal of this project.
What's also nice is that the require.context
approach should work out of the box right now, because it doesn't require any specific configuration within this plugin. It's simply leveraging a feature of webpack. So although I don't currently have a guide for how to do this it should be a viable option for anyone wanting to implement dynamic routes.
Once I rewrite my blog using this plugin I will definitely figure out how to do dynamic routing.
@iansinnott how would you do something like this for I18n routes? e.g. /about and /fr/about?
@lifeiscontent I'm not sure, but my guess is that Webpack has a i18n solution. Have you tried internationalizing a web app with webpack yet?
AKA routes that look like
The issue
We need dynamic routes to support creating an entire category of sties including blogs. However currently we don't have a way to turn something like
posts/:id
into a file directly. Normally we would have something like this:Which would generate the following HTML...
But in our case React Router has no way of knowing the contents of our
posts/
directory so how would it know what files to generate?Most static site generators would read the
posts/
directory and then generate static sites from those files. However, that requires the user to either learn how to configure their generator or learn the conventions for creating dynamic content.We could do the same thing:
But then the user would have to know how to hook into this process. It is a first-class goal of this project to not force the user to learn some new technology. Just add this plugin to a webpack config and go. This is the issue I'd like to solve.