More updates, let me post a discussion we had internally:
Jan 18
Hi folks,
Last week Eric, Ewoud and I met to speak about webpack packaging to find a suitable solution for a long-lasting issue.
Here is the summary I came with, it’s all from my memory so feel free to add anything I forget:
-
sub-packages - we all agree it would be beneficial for core, plugins, and packaging to create consumable sub-packages in the core. Those sub-packages should be versioned correctly and consume by core and plugins.
-
@foreman/vendor - package to manage and consume production npm-dependencies.
-
@foreman/vendor should be built into vendor.js without tree-shaking .
-
Potentially, we should be able to create only one rpm from @foreman/vendor instead rpm for each npm-dep.
-
Can create linting rules that block developers from importing packages directly when they exist in the @foreman/vendor.
-
@foreman/dev, @foreman/test, @foreman/build - packages that manage dev/test/build dependencies and supply tools for those environments.
-
Doesn’t necessarily mean they should be separate packages, can be done in one package.
-
@foreman/lib - Instead aliasing the
foremanReact
for imports, it would be more beneficial to have a documented sub-package with everything we want to share with plugins so we stay controlled about what plugins can use and what not. (tfm functions, components, helpers…). -
How core should consume plugins? We all agree it’s very odd that plugins are available to core outside of the node-scope. From one side we want plugins to act like npm-packages, but from the other side we don’t want to put them in the package.json since then we coupled the data that exists in the gem-files.
We talked about a solution when we search for plugins that have package.json in their root, and then we can runnpm install <plugin-location>
(without --save), so their code will exist in the core node_modules folder.
Because plugins won’t consume core (they will consume sub-packages that core uses as well), it makes sense now that core should consume the plugins and we won’t fall into a situation when they depend on each other.
Thanks!
Tomer Brisker
to me, Ewoud, Eric, Walden, John, Amir, Ohad
Jan 20
Thanks for the update! Great to hear there’s some progress, let’s get this in asap so we have time to handle any issues before 1.22.
Would be good to also update the rest of the community, either in response to the previous post or as a new post on discourse.
Eric Helms
to Tomer, me, Ewoud, Walden, John, Amir, Ohad
Jan 21
Avi,
As I learned more about Insights throughout last week, hearing the UI architecture got me to wondering if it would help solve our issues. The general idea for their design is there is a set of “chroming” that is the common shell, e.g. navigation and routing. Outside of the chroming aspect, each application (or plugin in our case) provides their own UI assets relying on common NPM packages similar to what we envision for foremanVendor and foremanLib. One of the differences being that instead of loading a core bundle and vendor JS that provides all of core’s UI pieces, each plugin would provide it’s UI JS and a vendorJS. Thus, each plugin is coupled to and built against it’s respectively built vendorJS and when a plugin page is loaded, that plugin’s JS is retrieved to load up the plugins pages and interactions. This provides greater independence for every plugin given they are using common components but not relying on a centralized set of built assets (e.g. compiled vendor and compiled library JS). If every plugin provides their own vendor and application JS they would be independent, and without any extra loading given the core JS bundles would not be loaded for every page (only on core Foreman pages).
That’s my interpretation of how it works, and how it could work for us giving plugins more independence and reducing build burden. Thoughts (from anyone)?
As Tomer mentioned, we should move this discussion and results back to upstream, but given this point is using Insights as a reference I started within this smaller thread.
Ohad Levy
to Eric, Tomer, me, Ewoud, Walden, John, Amir, Ohad
Jan 21
On Mon, Jan 21, 2019 at 4:56 PM Eric Helms <ehelms@redhat.com> wrote:
Avi,
As I learned more about Insights throughout last week, hearing the UI architecture got me to wondering if it would help solve our issues. The general idea for their design is there is a set of “chroming” that is the common shell, e.g. navigation and routing. Outside of the chroming aspect, each application (or plugin in our case) provides their own UI assets relying on common NPM packages similar to what we envision for foremanVendor and foremanLib. One of the differences being that instead of loading a core bundle and vendor JS that provides all of core’s UI pieces, each plugin would provide it’s UI JS and a vendorJS. Thus, each plugin is coupled to and built against it’s respectively built vendorJS and when a plugin page is loaded, that plugin’s JS is retrieved to load up the plugins pages and interactions. This provides greater independence for every plugin given they are using common components but not relying on a centralized set of built assets (e.g. compiled vendor and compiled library JS). If every plugin provides their own vendor and application JS they would be independent, and without any extra loading given the core JS bundles would not be loaded for every page (only on core Foreman pages).
That’s my interpretation of how it works, and how it could work for us giving plugins more independence and reducing build burden. Thoughts (from anyone)?
I think this is not that different approach from what we would like to end up at, my main question question would be around how to ensure we have a patternfly like place where everyone contribute reusable code to?
based on your explanation above, how is it that different from Avi’s plan? in my head:
-
foreman vendor is all of the common plugins client can use (e.g. common enough that it makes sense to include them once - e.g. react).
-
foreman bundle is the chroming, e.g. navigation and reusable components (e.g. charts, tables, api call logic, redux etc etc)
then each plugin is basically adding its own set of 1 (plugin specific libs) and 2 ( client specific behavior) ?
Eric Helms
to Ohad, Tomer, me, Ewoud, Walden, John, Amir
Jan 21
On Mon, Jan 21, 2019 at 10:08 AM Ohad Levy <olevy@redhat.com> wrote:
On Mon, Jan 21, 2019 at 4:56 PM Eric Helms <ehelms@redhat.com> wrote:
Avi,
As I learned more about Insights throughout last week, hearing the UI architecture got me to wondering if it would help solve our issues. The general idea for their design is there is a set of “chroming” that is the common shell, e.g. navigation and routing. Outside of the chroming aspect, each application (or plugin in our case) provides their own UI assets relying on common NPM packages similar to what we envision for foremanVendor and foremanLib. One of the differences being that instead of loading a core bundle and vendor JS that provides all of core’s UI pieces, each plugin would provide it’s UI JS and a vendorJS. Thus, each plugin is coupled to and built against it’s respectively built vendorJS and when a plugin page is loaded, that plugin’s JS is retrieved to load up the plugins pages and interactions. This provides greater independence for every plugin given they are using common components but not relying on a centralized set of built assets (e.g. compiled vendor and compiled library JS). If every plugin provides their own vendor and application JS they would be independent, and without any extra loading given the core JS bundles would not be loaded for every page (only on core Foreman pages).
That’s my interpretation of how it works, and how it could work for us giving plugins more independence and reducing build burden. Thoughts (from anyone)?
I think this is not that different approach from what we would like to end up at, my main question question would be around how to ensure we have a patternfly like place where everyone contribute reusable code to?
based on your explanation above, how is it that different from Avi’s plan? in my head:
foreman vendor is all of the common plugins client can use (e.g. common enough that it makes sense to include them once - e.g. react).
foreman bundle is the chroming, e.g. navigation and reusable components (e.g. charts, tables, api call logic, redux etc etc)
then each plugin is basically adding its own set of 1 (plugin specific libs) and 2 ( client specific behavior) ?
Exactly. That aspect of the plan does not change. I am looking at changing how we build the assets and then how we serve the assets. Today, we load a core set of JS bundles on every page load that contain both common components and Foreman core application code (e.g. page specific logic that is not re-usable). Those core set of compiled bundles are what plugins require, and build against, in order to run that has created this fragile dependency especially when plugin provided third party libraries are involved. What I am trying to suggest is a model where only code related to the navigation is loaded by default, and depending on the page being accessed determines what other JS bundles are loaded (e.g. core Foreman page logic + Foreman core vendor, Katello page logic + Katello’s vendor). I can try to draw a picture if that would help.
I’ll try to build out a slight example. Say we now have foremanLib with all common components, both foreman-bundle.js and katello-bundle.js would contain copies of foremanLIb with each respective set of code, foremanCore.js and katello.js linked against their respective bundles independently from one another. When on a Foreman core page, katello-bundle.js would not be loaded. On a Katello page, foreman-bundle.js would not be loaded either. Similarly, each wold have their own vendor.js that gets loaded depending on context, but not both together.
me
to Eric, Ohad, Tomer, Ewoud, Walden, John, Amir
Jan 23
Eric I love your suggestion and ideally, this how I would want to see it implemented.
You are basically describing SPA architecture when the routing and the navigation done in the client-side while it dynamically imports the relevant JS files needed for the current route.
Then we can use tree-shaking and let webpack create bundles and vendors for core and plugins. As you said we will end up with bigger bundles/vendors but they will be independent.
One of the issues I see is the fact pages are rendered by the server so when you want to use a react component you need to inject a javascript that take the component from a common registry and then mount it to the dom.
While I think it’s a good goal I believe we should stick to the current plan and migrate to an SPA approach when we will have more pages written with React.
Tomer Brisker
to me, Eric, Ohad, Ewoud, Walden, John, Amir
Jan 23
Let’s take the discussion to discourse so the rest of the community is aware of it, and most importantly lets start getting the code to solve this written and merged as soon as possible so we can get 1.22 working with webpack as early as possible before branching and have the time to fix any additional issues in either building, packaging, or elsewhere.