Front-end components RFC
The main problem for us in the front-end is about easily adding and removing components, while minimizing the work that needs to be done for a component to work.
As it stands, the user has no easy way to do this.
Eg. If I want the entirety of science blogger, but I want to add the book builder in the mix, I'll probably need to go in and play around with the code.
The proposal underneath intends to make the above scenario as usable as, (a) npm install bookbuilder
, (b) restart server.
The way we are thinking about it would break core into two different pieces.
- Core: The backend, essentially the API and the db with its models.
- UI: This will be the whole front-end, bar the components. This includes the infrastructure needed to serve components, ie. react, redux, webpack, sass etc.
The UI will require core, while also including the npm scripts (npm run etc). These scripts are currently included in the science blogger component. But if I include more npm scripts in my component, these might start conflicting with each other. The blogger also requires packages like webpack, which could just be done once in the UI and not once for each component. The separation will also make it easy for anyone to swap our entire redux ecosystem and build a UI in Angular or some other framework, and then build their own components for that, all while never having to do anything else in the backend apart from requiring core.
That means that what someone runs to run pubsweet generally in this scenario is the UI (as opposed to science blogger or some other component). The UI will require all necessary parts to make things work. Then depending on the installed components (and probably a config file or two), it will load the components the user wants.
The structure of a component in this setup would be dead simple, an enhanced equivalent of a folder in our current /app/components folder.
A component could, for example, include:
- The react components
- Routes that need to be added
- What redux actions to add to the front-end, if any
- Styling files
Then redux would, on start, look through the components and dynamically add / require all actions, dispatchers, routes.
We could also provide ready-made generic exports for common functionality that developers need.
First thing that comes to mind is redux actions, which could be as simple as:
import { Action } from 'somewhere'
const myAction = new Action({ options })
Additionally, we could have well-tested bundles of components. For example, science blogger would be a bundle of the blog component (manager, post list etc.) and the science writer.
The sticking point for us in all this was: How will the UI know which front-end components are there?
We could think of three different scenarios:
- Browse node_modules to find pubsweet front-end components. This will probably need a naming convention, like "pubsweet-ui-*".
- A command line tool that will fetch the component and install it in a dedicated folder, similar to how npm uses node_modules. ("pubsweet install bookbuilder")
- Simply npm install the component, but in a post install script, add its name to a config file in UI, so that it knows when it starts, what it has. This could have the added benefit of not having to uninstall a component to disable it, but being able to comment it out instead.
On a side note, since you guys mentioned it in the backend extensions RFC (#31 (closed)), the way we imagine it, front-end components and back-end extensions will be completely separate. INK for example, will need both to be developed. But the back-end INK extension should be able to work on its own, without touching the front-end. Then the front-end INK component will add some actions to redux to be able to access the INK-related API and will therefore require the back-end extension to work.