liferay / liferay-js-toolkit

GNU Lesser General Public License v3.0
52 stars 41 forks source link

Implement internal exports #583

Closed izaera closed 3 years ago

izaera commented 4 years ago

While developing #582 we have detected that there's a use case where an OSGi bundle wants to use its own JS modules for internal purposes, but doesn't want to export them for external use.

For example, account-admin-web needs these exports:

exports: {
    AccountEntriesManagementToolbarDefaultEventHandler:
        './account_entries_admin/js/AccountEntriesManagementToolbarDefaultEventHandler.es.js',
    AccountOrganizationsManagementToolbarDefaultEventHandler:
        './account_entries_admin/js/AccountOrganizationsManagementToolbarDefaultEventHandler.es.js',
    AccountRolesManagementToolbarDefaultEventHandler:
        './account_entries_admin/js/AccountRolesManagementToolbarDefaultEventHandler.es.js',
    AccountUsersManagementToolbarDefaultEventHandler:
        './account_entries_admin/js/AccountUsersManagementToolbarDefaultEventHandler.es.js',
    ManagementToolbarDefaultEventHandler:
        './account_users_admin/js/ManagementToolbarDefaultEventHandler.es.js',
},

so that code in JSPs like:

<liferay-frontend:component
    componentId="<%= viewAccountEntriesManagementToolbarDisplayContext.getDefaultEventHandler() %>"
    module="account_entries_admin/js/AccountEntriesManagementToolbarDefaultEventHandler.es"
/>

works.

Ideally we would like that:

  1. These exports are kept internal so that nobody outside account-admin-web uses them.
  2. These exports are automagically configured by the bundler
izaera commented 4 years ago

An idea that came to mind is to create internal webpack bundles + entry points which require each js module inside the project and reexports it. These would be called internal exports and would be generated automatically by the bundler.

Also, to honor 1, we would call these entry points something like internal_do_not_use/... or mangle their names using hashes to make people aware that they shouldn't consume them from other bundles.

wincent commented 4 years ago

create internal webpack bundles + entry points which require each js module inside the project and reexports it

Would these be "bundles" in the sense that they include their transitive dependencies? How would we avoid redundantly bundling the same dependencies over and over? And are you proposing autodetecting with modules should be entry points (due to internal usage), or just assuming that any module could be consumed internally?

jbalsas commented 4 years ago

[...] just assuming that any module could be consumed internally?

This πŸ‘†

How would we avoid redundantly bundling the same dependencies over and over?

I was hoping maybe we could configure webpack common chunks to deal with this...

wincent commented 4 years ago

I was hoping maybe we could configure webpack common chunks to deal with this...

I can't see how that would work then. Because if anything can be an entry point, then the entire dependency graph is probably reachable in multiple ways. There will be no leaf nodes, even, that could be packed into a common bundle, because any of those could be an entry point (and via induction, the same is true for any other module).

jbalsas commented 4 years ago

You might be right... any suggestion that comes to mind? We could always do this by convention rather than configuration...

izaera commented 4 years ago

Right now we only split in:

  1. one bundle per entry point
  2. one bundle with common code for all those in 1
  3. webpack runtime

Everything in 2 is loaded for every entry point, while all those in 1 are only loaded if the module is used.

AFAIK webpack may be configured more finely to have more than one bundle of type 2, but I haven't investigated it in depth yet.

So, with the current situation, it depends on the dependency graph how much optimization you can get with the two extreme scenarios being:

  1. Every entry point (type 1) is self sufficient and doesn't share code with the others: in this case we optimize tree shaking to the maximum as the shared bundle (type 2) would be empty and only code that is really used is loaded by the AMD loader.
  2. Two or more entry points share almost all (say 95%) of the code in the project: in this case webpack puts 95% of the code in the shared bundle and it gets loaded for any entry point (even if the entry point only uses one line of it).
izaera commented 4 years ago

As I said, if we fine tune webpack I think we may have more than one shared bundle and webpack takes care of loading only the subgraphs that are needed for each entry point.

:point_right: https://webpack.js.org/plugins/split-chunks-plugin/

izaera commented 4 years ago

I didn't read this :sweat_smile:

There will be no leaf nodes, even, that could be packed into a common bundle, because any of those could be an entry point (and via induction, the same is true for any other module).

izaera commented 4 years ago

However, I don't think it applies.

Because if webpack lets the bundles duplicate code, the tree shaking could be perfect at the cost of more size in the JAR (one bundle per entry point with only the needed subgraph; obviously with lots of duplication).

And then, you can have something between the middle with shared bundles that contain common code for a selected group of entry points. I'll attach a hand drawing to show what I mean.

wincent commented 4 years ago

Yeah, you'd have to try it and see what webpack does. Thinking about a small example graph:

A--B--C---*
 \     \   \
  D-----E---F
   \       /
    G-----*
     \
      H

Where A is the main entry point, and we'd need "bundles" for each of A through H. What does "perfect" tree-shaking mean in this scenario? ("one bundle per entry point with only the needed subgraph; obviously with lots of duplication" doesn't really sound perfect to me at all.)

izaera commented 4 years ago

Your ASCII art was faster than my webcam + GIMP editing :joy:

wincent commented 4 years ago

Depending on the connectivity of the graph, the level of redundancy in the bundles could be tremendous (at a glance, I'm thinking total size could grow quadratically, which with a big library could quickly become untenable).

izaera commented 4 years ago

Yes that's true.

izaera commented 4 years ago

The webpack split plugin has settings based on max/min size of the bundles and number of bundles needed to load the whole graph (to avoid several multiple connections).

Thinking about it, looks like perfect tree shaking is impossible for all scenarios. :thinking:

But it seems true that the more entry points you have, the more you will be constrained when tree shaking...

izaera commented 4 years ago

I would say that if we can't think of any other solution we can analyze what happens first and then decide if it is too horrible to implement it or we can live with it.

But if we can have another candidate solution before starting the analysis it would be great. :sweat_smile:

wincent commented 4 years ago

My intuition is that it is infeasible, even without trying it. I only mention seeing what webpack does out of curiosity.

skeptical

This feels like it's running into conflict with the original design motivation for the Liferay bundler/loader, and why we even have one. We have one because we can't know ahead of time what is going to be needed for a particular page, so we don't have the luxury of preparing prepacked, optimal bundles for each route on a site. So, we made this thing (v2) that has a build-time part (preparing individual modules for delivery) and a run-time part (the server-side registry the module resolver endpoint, and the combo servlet) which allow us to effectively make and deliver bundles on the fly.

v3 evolves that model a little bit by making these prebuilt bundles using webpack in the name of speeding up the build. But, what we're talking about in this PR goes waaaaay beyond that. It's right back in the territory of "we don't know ahead of time what's needed", but this time the answer isn't "figure it out just-in-time"; it's "prepare a bundle for every possible eventuality" β€” and my gut says that we're going to run afoul of quadratic growth if we try this.

I would say we need to keep the thinking cap on for a little bit on this one. 😬

izaera commented 4 years ago

Bad news: if we create multiple chunks (shared bundles) we need to load them. And to load them, we:

  1. need to know the subgraphs for each entry point (I believe webpack gives us this in the form of a manifest)
  2. need to load the chunks with the loader, which means that we don't want to be in the extreme situation I said (and @wincent mentioned here) because we would use huge amounts of RAM in the browser.

So, it seems like this will break the tree shaking no matter what we do...

izaera commented 4 years ago

"we don't know ahead of time what's needed"

:thinking: the truth is we may know it scanning the code, except for dynamically generated module names which we could:

  1. forbid
  2. warn about so that the user configures them by hand
izaera commented 4 years ago

By dynamically generated module names I mean things like:

<%
MyDisplayContext myDisplayContext = new MyDisplayContext();
%>

<aui:script require="<%= myDisplayContext.gimmeTheModuleName() %>"/>

which are not resolvable at build time, for obvious reasons.

wincent commented 4 years ago

we could:

  1. forbid
  2. warn about so that the user configures them by hand

So to know whether that is feasible, we'd need to know how many of them there are (not the exact number; just a ballpark figure), and I would also want to think through the implications for people using the bundler outside of liferay-portal repo.

izaera commented 4 years ago

We could delegate the parsing task to gradle/npm-scripts to make them create a correct configuration file for the bundler.

Also, if we want to make this internal exports less accessible, it's a matter of gradle/npm-scripts generating the correct entry point names as suggested here.

izaera commented 4 years ago

So to know whether that is feasible, we'd need to know how many of them there are

Any -web or -taglilb module have several as soon as they need to use JavaScript. I would say we don't even need to count them because it's the most usual pattern. :shrug:

using the bundler outside of liferay-portal repo

Yeah, that would leave the forbid option out, I think.

izaera commented 4 years ago

Still, I don't think it is usual to have dynamic module names. I'll look for them and report.

izaera commented 4 years ago

I would say that it is very unusual, but we should not forbid dynamic module names (just discourage them) because they may be needed when creating extensible interfaces. For instance, think of a multiplexing JSP that depending on the context renders a different JS module based on a configuration value. And people can contribute more JS modules with fragments after the JSP has been published. Things like that....

izaera commented 4 years ago

Another thing that comes to my mind is if the hypothesis that having more entry points is worse holds true....

All this is happening in the context of a single project so, unless people have dead core around in their projects, all of it will end up being loaded in one moment or other so, the worse thing that could happen is that we load more than we need in advance, not that we load unused things.

But it may not be so catastrophic as we think. Or at least not as catastrophic as it would be configuring all the JS files in react or angular as entry points.

wincent commented 4 years ago

But it may not be so catastrophic as we think. Or at least not as catastrophic as it would be configuring all the JS files in react or angular as entry points.

Pick something like layout-content-page-editor-web and see if it scales:

src
└── main
    └── resources
        └── META-INF
            └── resources
                └── page_editor
                    β”œβ”€β”€ app
                    β”‚Β Β  β”œβ”€β”€ actions
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addFragmentComposition.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addFragmentEntryLinkComment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addFragmentEntryLinks.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addMappedInfoItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addUsedWidgets.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteFragmentEntryLinkComment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteWidgets.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ duplicateItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editFragmentEntryLinkComment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ index.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ loadReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ moveItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ switchSidebarPanel.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ switchViewportSize.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ togglePermission.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ toggleShowResolvedComments.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ types.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ unloadReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateColSize.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateEditableValues.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateFragmentEntryLinkConfiguration.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateFragmentEntryLinkContent.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateItemConfig.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateLanguageId.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateLayoutData.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateNetwork.js
                    β”‚Β Β  β”‚Β Β  └── updatePageContents.js
                    β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ AllowedFragmentSelector.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ AllowedFragmentTreeNode.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ App.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionItemContext.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Controls.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ DisabledArea.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ DragPreview.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperimentsLabel.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Frame.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Layout.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ LayoutViewport.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ManageAllowedFragmentButton.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ManageAllowedFragmentModal.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ MasterLayout.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ NetworkStatusBar.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Sidebar.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Toolbar.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Topper.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ TopperEmpty.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Translation.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ UnsafeHTML.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ViewportSizeSelector.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ floating-toolbar
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionConfigurationPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ContainerConfigurationPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FloatingToolbar.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentConfigurationPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ImagePropertiesPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ LinkPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ MappingPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ RowConfigurationPanel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ SaveFragmentCompositionModal.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── SectionConfigurationPanel.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ fragment-configuration-fields
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CheckboxField.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionSelectorField.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ColorPaletteField.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ItemSelectorField.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ SelectField.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ TextField.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ fragment-content
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ EditableProcessorContext.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentContent.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentContentFloatingToolbar.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentContentInteractionsFilter.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentContentProcessor.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ getAllEditables.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ getEditableElement.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ getEditableElementId.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ getEditableUniqueId.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ isMapped.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── resolveEditableValue.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ layout-data-items
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Collection.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionItemWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Column.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ColumnOverlayGrid.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ColumnWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Container.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ContainerWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ DropZoneWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentsEditorShim.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Root.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Row.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ RowWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Section.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ SectionWithControls.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ hasDropZoneChild.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”‚Β Β  └── undo
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ Undo.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ UndoHistory.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ getActionLabel.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoActions.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoDelete.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoDuplicateItem.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoEditableValuesAction.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoFragmentConfiguration.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoFragmentEntryLinks.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoLayoutDataAction.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoSelectExperience.js
                    β”‚Β Β  β”‚Β Β      β”œβ”€β”€ undoUpdateLanguage.js
                    β”‚Β Β  β”‚Β Β      └── useUndo.js
                    β”‚Β Β  β”œβ”€β”€ config
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ constants
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ backgroundImageFragmentEntryProcessor.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ compatibleTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editableFloatingToolbarButtons.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editableFloatingToolbarClassNames.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editableFragmentEntryProcessor.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editableTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ floatingToolbarConfigurations.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ fragmentTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ freemarkerFragmentEntryProcessor.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ highlightedCommentIdKey.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itemActivationOrigins.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ itemTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ keycodes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ layoutDataFloatingToolbarButtons.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ layoutDataItemTypeLabels.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ layoutDataItemTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ moveItemDirections.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ pageTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ serviceNetworkStatusTypes.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ translationStatusType.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── viewportSizes.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ index.js
                    β”‚Β Β  β”œβ”€β”€ processors
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ BackgroundImageProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FallbackProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ HTMLProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ImageProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ LinkProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ RichTextProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ TextProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ getAlloyEditorProcessor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ getLinkableEditableEditorWrapper.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ reducers
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ baseReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ collectionsReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ fragmentEntryLinksReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ fragmentsReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ index.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ languageIdReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ languageReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ layoutDataReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ mappedInfoItemsReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ networkReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ pageContentsReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ permissionsReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectedViewportSizeReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ showResolvedCommentsReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ sidebarReducer.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ undoReducer.js
                    β”‚Β Β  β”‚Β Β  └── widgetsReducer.js
                    β”‚Β Β  β”œβ”€β”€ selectors
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectAvailablePanels.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectAvailableSidebarPanels.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectCanUpdate.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectCanUpdateLayoutContent.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectEditableValue.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectEditableValueConfig.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectEditableValueContent.js
                    β”‚Β Β  β”‚Β Β  └── selectSegmentsExperienceId.js
                    β”‚Β Β  β”œβ”€β”€ services
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionService.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperienceService.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentService.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ InfoItemService.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ LayoutService.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ WidgetService.js
                    β”‚Β Β  β”‚Β Β  └── serviceFetch.js
                    β”‚Β Β  β”œβ”€β”€ store
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ thunks
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addFragment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addFragmentComment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addFragmentComposition.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ addWidget.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteFragmentComment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ duplicateItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ editFragmentComment.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ moveItem.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ multipleUndo.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ resizeColumns.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ undo.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateEditableValues.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateFragmentConfiguration.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateItemConfig.js
                    β”‚Β Β  β”‚Β Β  └── updateRowColumns.js
                    β”‚Β Β  └── utils
                    β”‚Β Β      β”œβ”€β”€ getLayoutDataItemLabel.js
                    β”‚Β Β      β”œβ”€β”€ getResponsiveConfig.js
                    β”‚Β Β      β”œβ”€β”€ getWidgetPath.js
                    β”‚Β Β      β”œβ”€β”€ setWidgetUsage.js
                    β”‚Β Β      β”œβ”€β”€ useDragAndDrop.js
                    β”‚Β Β      β”œβ”€β”€ useId.js
                    β”‚Β Β      └── useParseURL.js
                    β”œβ”€β”€ common
                    β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Button.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Collapse.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionSelector.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ColorPalette.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Editor.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FormRow.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ImageSelector.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ InlineConfirm.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ InvisibleFieldset.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ItemSelector.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Loader.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ MappingSelector.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ SearchForm.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ SidebarPanelContent.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ SidebarPanelHeader.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ Textarea.js
                    β”‚Β Β  β”‚Β Β  └── UserIcon.js
                    β”‚Β Β  └── index.js
                    β”œβ”€β”€ core
                    β”‚Β Β  β”œβ”€β”€ AppContext.js
                    β”‚Β Β  β”œβ”€β”€ createDNDBackend.js
                    β”‚Β Β  β”œβ”€β”€ debounceRAF.js
                    β”‚Β Β  β”œβ”€β”€ hooks
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ useLazy.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ useLoad.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ usePlugins.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ useSetRef.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ useStateSafe.js
                    β”‚Β Β  β”‚Β Β  └── useThunk.js
                    β”‚Β Β  β”œβ”€β”€ openImageSelector.js
                    β”‚Β Β  └── openInfoItemSelector.js
                    β”œβ”€β”€ plugins
                    β”‚Β Β  β”œβ”€β”€ comments
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ AddCommentForm.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CommentForm.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CommentsSidebar.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ EditCommentForm.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentComment.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentComments.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentEntryLinksWithComments.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ NoCommentsMessage.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ NoCommentsMessageIcon.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ReplyCommentForm.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ResolveButton.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── ResolvedCommentsToggle.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ contents
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ContentsSidebar.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ NoPageContents.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ PageContent.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── PageContents.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ experience
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ actions
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ createExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ types.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── updateExperiencePriority.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ actions.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperienceItem.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperienceModal.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperienceSelector.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperienceToolbarSection.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperiencesList.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ ExperimentLabel.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── Popover.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ index.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ reducers
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ createExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ deleteExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ index.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateExperiencePriority.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── utils.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ statuses.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ thunks
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ createExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ removeExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ selectExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ updateExperience.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── updateExperiencePriority.js
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ types.js
                    β”‚Β Β  β”‚Β Β  └── utils.js
                    β”‚Β Β  β”œβ”€β”€ fragments
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ CollectionDisplay.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentCard.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ FragmentsSidebar.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── LayoutElements.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ mapping
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── MappingSidebar.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  β”œβ”€β”€ page-structure
                    β”‚Β Β  β”‚Β Β  β”œβ”€β”€ components
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ PageStructureSidebar.js
                    β”‚Β Β  β”‚Β Β  β”‚Β Β  └── StructureTreeNode.js
                    β”‚Β Β  β”‚Β Β  └── index.js
                    β”‚Β Β  └── widgets
                    β”‚Β Β      β”œβ”€β”€ components
                    β”‚Β Β      β”‚Β Β  β”œβ”€β”€ Widget.js
                    β”‚Β Β      β”‚Β Β  └── WidgetsSidebar.js
                    β”‚Β Β      └── index.js
                    └── prop-types
                        β”œβ”€β”€ BackgroundImagePropTypes.js
                        β”œβ”€β”€ ConfigurationFieldPropTypes.js
                        β”œβ”€β”€ LayoutDataPropTypes.js
                        β”œβ”€β”€ getEditableItemPropTypes.js
                        β”œβ”€β”€ getLayoutDataItemPropTypes.js
                        └── index.js

45 directories, 296 files
izaera commented 4 years ago

As expected, with the current setup, everything ends up in the vendor.bundle.js file, which the one and only shared chunk we allow webpack to generate (as it is now).

Then, there is one single line webpack bundle per entry point (referring to the vendor bundle) plus an additional bridge to make it available through the loader.

So:

  1. No tree shaking
  2. Double indirection when requesting a module

Seems worse than bundler 2.

Now I'm going to tweak the SplitChunksPlugin to see what happens :crossed_fingers: .

izaera commented 4 years ago

I have made a test with just 5 entry points:

    exports: {
        __page_editor_common_index_js: './page_editor/common/index.js',
        __page_editor_common_components_UserIcon_js: './page_editor/common/components/UserIcon.js',
        __page_editor_common_components_Collapse_js: './page_editor/common/components/Collapse.js',
        __page_editor_common_components_InvisibleFieldset_js: './page_editor/common/components/InvisibleFieldset.js',
        __page_editor_common_components_SidebarPanelHeader_js: './page_editor/common/components/SidebarPanelHeader.js',
    }

And the result has been an empty vendor bundle (no shared code) and replication of some code inside the entry point bundles.

So, for example, both index.js and Collapse.js bundles contain the code for the original Collapse.js file, as it can be in the following executions of wp-inspect (a script I've made to dump the contents of a webpack bundle file):

$ wp-inspect build/node/packageRunBuild/resources/__page_editor_common_index_js.bundle.js
AMD module name:
    layout-content-page-editor-web@2.0.34/__page_editor_common_index_js.bundle
AMD dependencies:
    module
    require
    ./webpack.manifest
    frontend-js-react-web$react
    frontend-js-react-web$prop-types
    frontend-js-react-web$classnames
    @frontend-taglib-clay$clayui/icon
    @frontend-taglib-clay$clayui/form
Webpack entry [ '__page_editor_common_index_js' ] :
    Implementations:
        ./build/node/bundler/generated/__page_editor_common_index_js.js
        ./src/main/resources/META-INF/resources/page_editor/common/components/Collapse.js
        ./src/main/resources/META-INF/resources/page_editor/common/components/SearchForm.js
        ./src/main/resources/META-INF/resources/page_editor/common/components/SidebarPanelHeader.js
        ./src/main/resources/META-INF/resources/page_editor/common/index.js

and

$ wp-inspect build/node/packageRunBuild/resources/__page_editor_common_components_Collapse_js.bundle.js 
AMD module name:
    layout-content-page-editor-web@2.0.34/__page_editor_common_components_Collapse_js.bundle
AMD dependencies:
    module
    require
    ./webpack.manifest
    frontend-js-react-web$react
    frontend-js-react-web$prop-types
    frontend-js-react-web$classnames
    @frontend-taglib-clay$clayui/icon
Webpack entry [ '__page_editor_common_components_Collapse_js' ] :
    Implementations:
        ./build/node/bundler/generated/__page_editor_common_components_Collapse_js.js
        ./src/main/resources/META-INF/resources/page_editor/common/components/Collapse.js
izaera commented 4 years ago

Conclusions:

  1. The SplitChunksPlugin decides how to split the bundles based on the constraints the user configures (as specified in its documentation) and it may decide to duplicate or share code depending on its algorithm.

~2. Exporting all modules is -with high probability- going to make webpack to put all the shared code in a bundle and load it from every entry point.~ (edited because of the reasons given in the last lines of this comment).

  1. We should probably provide some mean for the end user to specify how many chunks he wants and how to distribute them, though it will make the bundler more complex, because we won't be able to assume that only one vendor.bundle.js exists, thus we need to decide which shared bundles to load and when.
wincent commented 4 years ago

despair

Well, that just sucks.

izaera commented 4 years ago

Changing the configuration of the plugin alters how the bundles are split. For example, if I use the settings in this example:

{
optimization: {
        splitChunks: {
            chunks: "all",
            maxInitialRequests: 20, // for HTTP2
            maxAsyncRequests: 20, // for HTTP2
            minSize: 40 // for example only: chosen to match 2 modules
            // omit minSize in real use case to use the default of 30kb
        }
    }
}

I don't get the duplication any more, because the common code for Collapse.js is put in a separate bundle:

__page_editor_common_components_Collapse_js.bundle.js
__page_editor_common_components_Collapse_js~__page_editor_common_index_js.bundle.js
__page_editor_common_components_InvisibleFieldset_js.bundle.js
__page_editor_common_components_SidebarPanelHeader_js.bundle.js
__page_editor_common_components_SidebarPanelHeader_js~__page_editor_common_index_js.bundle.js
__page_editor_common_components_UserIcon_js.bundle.js
__page_editor_common_index_js.bundle.js
runtime.bundle.js

Sadly, it looks like I was looking at the wrong directory and my first test is not relevant (this one specifically).

However, the second and third (this) are right and the conclusions in this comment still hold except for number 2.

wincent commented 4 years ago

If it's not too hard, and because you have this neat tool to dump the output, would now be the right time to stress test this a little bit with a challenging example (like the layout-content-page-editor-web example that I mentioned earlier)?

izaera commented 4 years ago

I've done that and it does magic. So much magic that I can't understand anything :sweat_smile: .

If I force it to having more bundles at the cost of having more network request, it looks like the splitting is superb. In particular, with all files exported as entry points I get all these chunks in webpack's output directory:

__page_editor_app_actions_addFragmentComposition_js.bundle.js
__page_editor_app_actions_addFragmentComposition_js~__page_editor_app_actions_addFragmentEntryLinkCo~8bbc10ae.bundle.js
__page_editor_app_actions_addFragmentComposition_js~__page_editor_app_actions_index_js~__page_editor~52e05c40.bundle.js
__page_editor_app_actions_addFragmentEntryLinkComment_js.bundle.js
__page_editor_app_actions_addFragmentEntryLinkComment_js~__page_editor_app_actions_index_js~__page_e~fb5eddd9.bundle.js
__page_editor_app_actions_addFragmentEntryLinks_js.bundle.js
__page_editor_app_actions_addFragmentEntryLinks_js~__page_editor_app_actions_index_js~__page_editor_~d8d31b2c.bundle.js
__page_editor_app_actions_addItem_js.bundle.js
__page_editor_app_actions_addMappedInfoItem_js.bundle.js
__page_editor_app_actions_addMappedInfoItem_js~__page_editor_app_actions_index_js~__page_editor_app_~ca3c8b1e.bundle.js
__page_editor_app_actions_addUsedWidgets_js.bundle.js
__page_editor_app_actions_deleteFragmentEntryLinkComment_js.bundle.js
__page_editor_app_actions_deleteFragmentEntryLinkComment_js~__page_editor_app_actions_index_js~__pag~f4180d21.bundle.js
__page_editor_app_actions_deleteItem_js.bundle.js
__page_editor_app_actions_deleteWidgets_js.bundle.js
__page_editor_app_actions_duplicateItem_js.bundle.js
__page_editor_app_actions_editFragmentEntryLinkComment_js.bundle.js
__page_editor_app_actions_editFragmentEntryLinkComment_js~__page_editor_app_actions_index_js~__page_~2122682e.bundle.js
__page_editor_app_actions_index_js.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_loadReducer_js~__page_editor_app_compon~22a7733f.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_switchSidebarPanel_js~__page_editor_app~e09e580d.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_switchViewportSize_js~__page_editor_app~9dd49b9c.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_toggleShowResolvedComments_js~__page_ed~6678419d.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_unloadReducer_js~__page_editor_app_comp~8bdae623.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_updateColSize_js~__page_editor_app_comp~00901c62.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_updateEditableValues_js~__page_editor_a~7d8a279c.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_updateFragmentEntryLinkContent_js~__pag~dca60c80.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_updateLanguageId_js~__page_editor_app_c~138fdcc7.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_updateLayoutData_js~__page_editor_app_c~ff891ccd.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_actions_updateNetwork_js~__page_editor_app_comp~b4120c31.bundle.js
__page_editor_app_actions_index_js~__page_editor_app_components_undo_undoUpdateLanguage_js.bundle.js
__page_editor_app_actions_loadReducer_js.bundle.js
__page_editor_app_actions_moveItem_js.bundle.js
__page_editor_app_actions_switchSidebarPanel_js.bundle.js
__page_editor_app_actions_switchViewportSize_js.bundle.js
__page_editor_app_actions_togglePermission_js.bundle.js
__page_editor_app_actions_toggleShowResolvedComments_js.bundle.js
__page_editor_app_actions_types_js.bundle.js
__page_editor_app_actions_unloadReducer_js.bundle.js
__page_editor_app_actions_updateColSize_js.bundle.js
__page_editor_app_actions_updateEditableValues_js.bundle.js
__page_editor_app_actions_updateFragmentEntryLinkConfiguration_js.bundle.js
__page_editor_app_actions_updateFragmentEntryLinkContent_js.bundle.js
__page_editor_app_actions_updateItemConfig_js.bundle.js
__page_editor_app_actions_updateLanguageId_js.bundle.js
__page_editor_app_actions_updateLayoutData_js.bundle.js
__page_editor_app_actions_updateNetwork_js.bundle.js
__page_editor_app_actions_updatePageContents_js.bundle.js
__page_editor_app_components_AllowedFragmentSelector_js.bundle.js
__page_editor_app_components_AllowedFragmentSelector_js~__page_editor_app_components_App_js~__page_e~e5c8a31f.bundle.js
__page_editor_app_components_AllowedFragmentTreeNode_js.bundle.js
__page_editor_app_components_App_js.bundle.js
__page_editor_app_components_CollectionItemContext_js.bundle.js
__page_editor_app_components_Controls_js.bundle.js
__page_editor_app_components_DisabledArea_js.bundle.js
__page_editor_app_components_DragPreview_js.bundle.js
__page_editor_app_components_ExperimentsLabel_js.bundle.js
__page_editor_app_components_floating_toolbar_CollectionConfigurationPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_ContainerConfigurationPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_FloatingToolbar_js.bundle.js
__page_editor_app_components_floating_toolbar_FragmentConfigurationPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_ImagePropertiesPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_LinkPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_MappingPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_RowConfigurationPanel_js.bundle.js
__page_editor_app_components_floating_toolbar_SaveFragmentCompositionModal_js.bundle.js
__page_editor_app_components_floating_toolbar_SectionConfigurationPanel_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~06f68a98.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~07525cbe.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~28d9423a.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~65dc546c.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~708aa4d7.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~95e9c79f.bundle.js
__page_editor_app_components_fragment_configuration_fields_CheckboxField_js~__page_editor_app_compon~cf55b5a4.bundle.js
__page_editor_app_components_fragment_configuration_fields_CollectionSelectorField_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_ColorPaletteField_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_ColorPaletteField_js~__page_editor_app_ut~1a3ee97b.bundle.js
__page_editor_app_components_fragment_configuration_fields_ColorPaletteField_js~__page_editor_common~f4fcf996.bundle.js
__page_editor_app_components_fragment_configuration_fields_index_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_ItemSelectorField_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_SelectField_js.bundle.js
__page_editor_app_components_fragment_configuration_fields_TextField_js.bundle.js
__page_editor_app_components_fragment_content_EditableProcessorContext_js.bundle.js
__page_editor_app_components_fragment_content_FragmentContentFloatingToolbar_js.bundle.js
__page_editor_app_components_fragment_content_FragmentContentInteractionsFilter_js.bundle.js
__page_editor_app_components_fragment_content_FragmentContent_js.bundle.js
__page_editor_app_components_fragment_content_FragmentContentProcessor_js.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_config_constants_~e3f2a7af.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_Backgr~a3fc757e.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_Backgr~e3871234.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_Fallba~264817bf.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_HTMLPr~8854422f.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_ImageP~29882f09.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_index_js.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_LinkPr~00dbd2b4.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_LinkPr~380c90ce.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_LinkPr~c817ea8d.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_RichTe~4092e0e4.bundle.js
__page_editor_app_components_fragment_content_getAllEditables_js~__page_editor_app_processors_TextPr~214359dd.bundle.js
__page_editor_app_components_fragment_content_getEditableElementId_js.bundle.js
__page_editor_app_components_fragment_content_getEditableElement_js.bundle.js
__page_editor_app_components_fragment_content_getEditableUniqueId_js.bundle.js
__page_editor_app_components_fragment_content_isMapped_js.bundle.js
__page_editor_app_components_fragment_content_resolveEditableValue_js.bundle.js
__page_editor_app_components_Frame_js.bundle.js
__page_editor_app_components_layout_data_items_CollectionItemWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_Collection_js.bundle.js
__page_editor_app_components_layout_data_items_CollectionWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_Column_js.bundle.js
__page_editor_app_components_layout_data_items_ColumnOverlayGrid_js.bundle.js
__page_editor_app_components_layout_data_items_ColumnOverlayGrid_js~__page_editor_app_components_lay~3247b8e5.bundle.js
__page_editor_app_components_layout_data_items_ColumnWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_Container_js.bundle.js
__page_editor_app_components_layout_data_items_ContainerWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_DropZoneWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_FragmentsEditorShim_js.bundle.js
__page_editor_app_components_layout_data_items_FragmentWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_hasDropZoneChild_js.bundle.js
__page_editor_app_components_layout_data_items_hasDropZoneChild_js~__page_editor_app_config_constant~5fa95d1f.bundle.js
__page_editor_app_components_layout_data_items_index_js.bundle.js
__page_editor_app_components_layout_data_items_Root_js.bundle.js
__page_editor_app_components_layout_data_items_Row_js.bundle.js
__page_editor_app_components_layout_data_items_RowWithControls_js.bundle.js
__page_editor_app_components_layout_data_items_Section_js.bundle.js
__page_editor_app_components_layout_data_items_SectionWithControls_js.bundle.js
__page_editor_app_components_Layout_js.bundle.js
__page_editor_app_components_LayoutViewport_js.bundle.js
__page_editor_app_components_ManageAllowedFragmentButton_js.bundle.js
__page_editor_app_components_ManageAllowedFragmentModal_js.bundle.js
__page_editor_app_components_MasterLayout_js.bundle.js
__page_editor_app_components_NetworkStatusBar_js.bundle.js
__page_editor_app_components_NetworkStatusBar_js~__page_editor_app_config_constants_serviceNetworkSt~abda65a5.bundle.js
__page_editor_app_components_Sidebar_js.bundle.js
__page_editor_app_components_Toolbar_js.bundle.js
__page_editor_app_components_TopperEmpty_js.bundle.js
__page_editor_app_components_Topper_js.bundle.js
__page_editor_app_components_Translation_js.bundle.js
__page_editor_app_components_Translation_js~__page_editor_app_components_fragment_content_getAllEdit~01bc661c.bundle.js
__page_editor_app_components_undo_getActionLabel_js.bundle.js
__page_editor_app_components_undo_getActionLabel_js~__page_editor_plugins_experience_actions_js~__pa~a69a6d2f.bundle.js
__page_editor_app_components_undo_undoActions_js.bundle.js
__page_editor_app_components_undo_undoDelete_js.bundle.js
__page_editor_app_components_undo_undoDuplicateItem_js.bundle.js
__page_editor_app_components_undo_undoEditableValuesAction_js.bundle.js
__page_editor_app_components_undo_undoFragmentConfiguration_js.bundle.js
__page_editor_app_components_undo_undoFragmentEntryLinks_js.bundle.js
__page_editor_app_components_undo_UndoHistory_js.bundle.js
__page_editor_app_components_undo_Undo_js.bundle.js
__page_editor_app_components_undo_undoLayoutDataAction_js.bundle.js
__page_editor_app_components_undo_undoSelectExperience_js.bundle.js
__page_editor_app_components_undo_undoUpdateLanguage_js.bundle.js
__page_editor_app_components_undo_useUndo_js.bundle.js
__page_editor_app_components_UnsafeHTML_js.bundle.js
__page_editor_app_components_ViewportSizeSelector_js.bundle.js
__page_editor_app_config_constants_backgroundImageFragmentEntryProcessor_js.bundle.js
__page_editor_app_config_constants_compatibleTypes_js.bundle.js
__page_editor_app_config_constants_editableFloatingToolbarButtons_js.bundle.js
__page_editor_app_config_constants_editableFloatingToolbarClassNames_js.bundle.js
__page_editor_app_config_constants_editableFragmentEntryProcessor_js.bundle.js
__page_editor_app_config_constants_editableTypes_js.bundle.js
__page_editor_app_config_constants_floatingToolbarConfigurations_js.bundle.js
__page_editor_app_config_constants_fragmentTypes_js.bundle.js
__page_editor_app_config_constants_freemarkerFragmentEntryProcessor_js.bundle.js
__page_editor_app_config_constants_highlightedCommentIdKey_js.bundle.js
__page_editor_app_config_constants_itemActivationOrigins_js.bundle.js
__page_editor_app_config_constants_itemTypes_js.bundle.js
__page_editor_app_config_constants_keycodes_js.bundle.js
__page_editor_app_config_constants_layoutDataFloatingToolbarButtons_js.bundle.js
__page_editor_app_config_constants_layoutDataItemTypeLabels_js.bundle.js
__page_editor_app_config_constants_layoutDataItemTypeLabels_js~__page_editor_app_utils_getLayoutData~20ce4e0c.bundle.js
__page_editor_app_config_constants_layoutDataItemTypes_js.bundle.js
__page_editor_app_config_constants_moveItemDirections_js.bundle.js
__page_editor_app_config_constants_pageTypes_js.bundle.js
__page_editor_app_config_constants_serviceNetworkStatusTypes_js.bundle.js
__page_editor_app_config_constants_translationStatusType_js.bundle.js
__page_editor_app_config_constants_viewportSizes_js.bundle.js
__page_editor_app_config_constants_viewportSizes_js~__page_editor_app_utils_getResponsiveConfig_js.bundle.js
__page_editor_app_config_index_js.bundle.js
__page_editor_app_index_js.bundle.js
__page_editor_app_processors_BackgroundImageProcessor_js.bundle.js
__page_editor_app_processors_FallbackProcessor_js.bundle.js
__page_editor_app_processors_getAlloyEditorProcessor_js.bundle.js
__page_editor_app_processors_getLinkableEditableEditorWrapper_js.bundle.js
__page_editor_app_processors_HTMLProcessor_js.bundle.js
__page_editor_app_processors_ImageProcessor_js.bundle.js
__page_editor_app_processors_index_js.bundle.js
__page_editor_app_processors_LinkProcessor_js.bundle.js
__page_editor_app_processors_RichTextProcessor_js.bundle.js
__page_editor_app_processors_TextProcessor_js.bundle.js
__page_editor_app_reducers_baseReducer_js.bundle.js
__page_editor_app_reducers_collectionsReducer_js.bundle.js
__page_editor_app_reducers_fragmentEntryLinksReducer_js.bundle.js
__page_editor_app_reducers_fragmentsReducer_js.bundle.js
__page_editor_app_reducers_index_js.bundle.js
__page_editor_app_reducers_languageIdReducer_js.bundle.js
__page_editor_app_reducers_languageReducer_js.bundle.js
__page_editor_app_reducers_layoutDataReducer_js.bundle.js
__page_editor_app_reducers_mappedInfoItemsReducer_js.bundle.js
__page_editor_app_reducers_networkReducer_js.bundle.js
__page_editor_app_reducers_pageContentsReducer_js.bundle.js
__page_editor_app_reducers_permissionsReducer_js.bundle.js
__page_editor_app_reducers_selectedViewportSizeReducer_js.bundle.js
__page_editor_app_reducers_showResolvedCommentsReducer_js.bundle.js
__page_editor_app_reducers_sidebarReducer_js.bundle.js
__page_editor_app_reducers_undoReducer_js.bundle.js
__page_editor_app_reducers_widgetsReducer_js.bundle.js
__page_editor_app_reducers_widgetsReducer_js~__page_editor_app_utils_getWidgetPath_js.bundle.js
__page_editor_app_reducers_widgetsReducer_js~__page_editor_app_utils_setWidgetUsage_js.bundle.js
__page_editor_app_selectors_selectAvailablePanels_js.bundle.js
__page_editor_app_selectors_selectAvailablePanels_js~__page_editor_app_selectors_selectAvailableSide~ac5968d2.bundle.js
__page_editor_app_selectors_selectAvailableSidebarPanels_js.bundle.js
__page_editor_app_selectors_selectCanUpdate_js.bundle.js
__page_editor_app_selectors_selectCanUpdateLayoutContent_js.bundle.js
__page_editor_app_selectors_selectEditableValueConfig_js.bundle.js
__page_editor_app_selectors_selectEditableValueConfig_js~__page_editor_app_selectors_selectEditableV~b6d0eac4.bundle.js
__page_editor_app_selectors_selectEditableValueContent_js.bundle.js
__page_editor_app_selectors_selectEditableValue_js.bundle.js
__page_editor_app_selectors_selectSegmentsExperienceId_js.bundle.js
__page_editor_app_services_CollectionService_js.bundle.js
__page_editor_app_services_ExperienceService_js.bundle.js
__page_editor_app_services_FragmentService_js.bundle.js
__page_editor_app_services_InfoItemService_js.bundle.js
__page_editor_app_services_LayoutService_js.bundle.js
__page_editor_app_services_serviceFetch_js.bundle.js
__page_editor_app_services_WidgetService_js.bundle.js
__page_editor_app_store_index_js.bundle.js
__page_editor_app_thunks_addFragmentComment_js.bundle.js
__page_editor_app_thunks_addFragmentComposition_js.bundle.js
__page_editor_app_thunks_addFragment_js.bundle.js
__page_editor_app_thunks_addItem_js.bundle.js
__page_editor_app_thunks_addWidget_js.bundle.js
__page_editor_app_thunks_deleteFragmentComment_js.bundle.js
__page_editor_app_thunks_deleteItem_js.bundle.js
__page_editor_app_thunks_duplicateItem_js.bundle.js
__page_editor_app_thunks_editFragmentComment_js.bundle.js
__page_editor_app_thunks_moveItem_js.bundle.js
__page_editor_app_thunks_multipleUndo_js.bundle.js
__page_editor_app_thunks_resizeColumns_js.bundle.js
__page_editor_app_thunks_undo_js.bundle.js
__page_editor_app_thunks_updateEditableValues_js.bundle.js
__page_editor_app_thunks_updateFragmentConfiguration_js.bundle.js
__page_editor_app_thunks_updateItemConfig_js.bundle.js
__page_editor_app_thunks_updateRowColumns_js.bundle.js
__page_editor_app_utils_getLayoutDataItemLabel_js.bundle.js
__page_editor_app_utils_getResponsiveConfig_js.bundle.js
__page_editor_app_utils_getWidgetPath_js.bundle.js
__page_editor_app_utils_setWidgetUsage_js.bundle.js
__page_editor_app_utils_useDragAndDrop_js.bundle.js
__page_editor_app_utils_useId_js.bundle.js
__page_editor_app_utils_useParseURL_js.bundle.js
__page_editor_common_components_Button_js.bundle.js
__page_editor_common_components_Button_js~__page_editor_common_components_InlineConfirm_js~__page_ed~20f79c11.bundle.js
__page_editor_common_components_Button_js~__page_editor_common_components_InlineConfirm_js~__page_ed~de566fe5.bundle.js
__page_editor_common_components_Collapse_js.bundle.js
__page_editor_common_components_Collapse_js~__page_editor_common_index_js.bundle.js
__page_editor_common_components_CollectionSelector_js.bundle.js
__page_editor_common_components_ColorPalette_js.bundle.js
__page_editor_common_components_Editor_js.bundle.js
__page_editor_common_components_Editor_js~__page_editor_plugins_comments_components_CommentForm_js.bundle.js
__page_editor_common_components_FormRow_js.bundle.js
__page_editor_common_components_ImageSelector_js.bundle.js
__page_editor_common_components_InlineConfirm_js.bundle.js
__page_editor_common_components_InvisibleFieldset_js.bundle.js
__page_editor_common_components_InvisibleFieldset_js~__page_editor_plugins_comments_components_CommentForm_js.bundle.js
__page_editor_common_components_ItemSelector_js.bundle.js
__page_editor_common_components_Loader_js.bundle.js
__page_editor_common_components_MappingSelector_js.bundle.js
__page_editor_common_components_SearchForm_js.bundle.js
__page_editor_common_components_SearchForm_js~__page_editor_common_index_js.bundle.js
__page_editor_common_components_SidebarPanelContent_js.bundle.js
__page_editor_common_components_SidebarPanelContent_js~__page_editor_plugins_mapping_components_Mapp~fc55a771.bundle.js
__page_editor_common_components_SidebarPanelHeader_js.bundle.js
__page_editor_common_components_SidebarPanelHeader_js~__page_editor_common_index_js~__page_editor_pl~80927b30.bundle.js
__page_editor_common_components_Textarea_js.bundle.js
__page_editor_common_components_UserIcon_js.bundle.js
__page_editor_common_index_js.bundle.js
__page_editor_core_AppContext_js.bundle.js
__page_editor_core_AppContext_js~__page_editor_plugins_mapping_index_js.bundle.js
__page_editor_core_createDNDBackend_js.bundle.js
__page_editor_core_debounceRAF_js.bundle.js
__page_editor_core_hooks_useLazy_js.bundle.js
__page_editor_core_hooks_useLoad_js.bundle.js
__page_editor_core_hooks_usePlugins_js.bundle.js
__page_editor_core_hooks_useSetRef_js.bundle.js
__page_editor_core_hooks_useStateSafe_js.bundle.js
__page_editor_core_hooks_useThunk_js.bundle.js
__page_editor_core_openImageSelector_js.bundle.js
__page_editor_core_openInfoItemSelector_js.bundle.js
__page_editor_plugins_comments_components_AddCommentForm_js.bundle.js
__page_editor_plugins_comments_components_CommentForm_js.bundle.js
__page_editor_plugins_comments_components_CommentsSidebar_js.bundle.js
__page_editor_plugins_comments_components_EditCommentForm_js.bundle.js
__page_editor_plugins_comments_components_FragmentComment_js.bundle.js
__page_editor_plugins_comments_components_FragmentComments_js.bundle.js
__page_editor_plugins_comments_components_FragmentEntryLinksWithComments_js.bundle.js
__page_editor_plugins_comments_components_NoCommentsMessageIcon_js.bundle.js
__page_editor_plugins_comments_components_NoCommentsMessageIcon_js~__page_editor_plugins_comments_co~f26625e8.bundle.js
__page_editor_plugins_comments_components_NoCommentsMessage_js.bundle.js
__page_editor_plugins_comments_components_ReplyCommentForm_js.bundle.js
__page_editor_plugins_comments_components_ResolveButton_js.bundle.js
__page_editor_plugins_comments_components_ResolvedCommentsToggle_js.bundle.js
__page_editor_plugins_comments_index_js.bundle.js
__page_editor_plugins_contents_components_ContentsSidebar_js.bundle.js
__page_editor_plugins_contents_components_NoPageContents_js.bundle.js
__page_editor_plugins_contents_components_PageContent_js.bundle.js
__page_editor_plugins_contents_components_PageContents_js.bundle.js
__page_editor_plugins_contents_index_js.bundle.js
__page_editor_plugins_experience_actions_createExperience_js.bundle.js
__page_editor_plugins_experience_actions_createExperience_js~__page_editor_plugins_experience_action~24e0eecf.bundle.js
__page_editor_plugins_experience_actions_deleteExperience_js.bundle.js
__page_editor_plugins_experience_actions_js.bundle.js
__page_editor_plugins_experience_actions_selectExperience_js.bundle.js
__page_editor_plugins_experience_actions_types_js.bundle.js
__page_editor_plugins_experience_actions_updateExperience_js.bundle.js
__page_editor_plugins_experience_actions_updateExperiencePriority_js.bundle.js
__page_editor_plugins_experience_components_ExperienceItem_js.bundle.js
__page_editor_plugins_experience_components_ExperienceItem_js~__page_editor_plugins_experience_compo~259decba.bundle.js
__page_editor_plugins_experience_components_ExperienceItem_js~__page_editor_plugins_experience_compo~382b8a0d.bundle.js
__page_editor_plugins_experience_components_ExperienceItem_js~__page_editor_plugins_experience_compo~6afa04c8.bundle.js
__page_editor_plugins_experience_components_ExperienceItem_js~__page_editor_plugins_experience_compo~c9a36109.bundle.js
__page_editor_plugins_experience_components_ExperienceModal_js.bundle.js
__page_editor_plugins_experience_components_ExperienceSelector_js.bundle.js
__page_editor_plugins_experience_components_ExperiencesList_js.bundle.js
__page_editor_plugins_experience_components_ExperienceToolbarSection_js.bundle.js
__page_editor_plugins_experience_components_ExperimentLabel_js.bundle.js
__page_editor_plugins_experience_components_Popover_js.bundle.js
__page_editor_plugins_experience_index_js.bundle.js
__page_editor_plugins_experience_reducers_createExperience_js.bundle.js
__page_editor_plugins_experience_reducers_createExperience_js~__page_editor_plugins_experience_reduc~313e599c.bundle.js
__page_editor_plugins_experience_reducers_createExperience_js~__page_editor_plugins_experience_reduc~8d26602f.bundle.js
__page_editor_plugins_experience_reducers_deleteExperience_js.bundle.js
__page_editor_plugins_experience_reducers_deleteExperience_js~__page_editor_plugins_experience_reduc~3fc74691.bundle.js
__page_editor_plugins_experience_reducers_index_js.bundle.js
__page_editor_plugins_experience_reducers_index_js~__page_editor_plugins_experience_reducers_selectE~8a7eb176.bundle.js
__page_editor_plugins_experience_reducers_index_js~__page_editor_plugins_experience_reducers_updateE~4f051fd9.bundle.js
__page_editor_plugins_experience_reducers_index_js~__page_editor_plugins_experience_reducers_updateE~f12de0f1.bundle.js
__page_editor_plugins_experience_reducers_selectExperience_js.bundle.js
__page_editor_plugins_experience_reducers_updateExperience_js.bundle.js
__page_editor_plugins_experience_reducers_updateExperiencePriority_js.bundle.js
__page_editor_plugins_experience_reducers_utils_js.bundle.js
__page_editor_plugins_experience_statuses_js.bundle.js
__page_editor_plugins_experience_thunks_createExperience_js.bundle.js
__page_editor_plugins_experience_thunks_removeExperience_js.bundle.js
__page_editor_plugins_experience_thunks_selectExperience_js.bundle.js
__page_editor_plugins_experience_thunks_updateExperience_js.bundle.js
__page_editor_plugins_experience_thunks_updateExperiencePriority_js.bundle.js
__page_editor_plugins_experience_types_js.bundle.js
__page_editor_plugins_experience_utils_js.bundle.js
__page_editor_plugins_fragments_components_CollectionDisplay_js.bundle.js
__page_editor_plugins_fragments_components_FragmentCard_js.bundle.js
__page_editor_plugins_fragments_components_FragmentsSidebar_js.bundle.js
__page_editor_plugins_fragments_components_LayoutElements_js.bundle.js
__page_editor_plugins_fragments_index_js.bundle.js
__page_editor_plugins_mapping_components_MappingSidebar_js.bundle.js
__page_editor_plugins_mapping_components_MappingSidebar_js~__page_editor_plugins_mapping_index_js.bundle.js
__page_editor_plugins_mapping_index_js.bundle.js
__page_editor_plugins_page_structure_components_PageStructureSidebar_js.bundle.js
__page_editor_plugins_page_structure_components_StructureTreeNode_js.bundle.js
__page_editor_plugins_page_structure_index_js.bundle.js
__page_editor_plugins_widgets_components_Widget_js.bundle.js
__page_editor_plugins_widgets_components_WidgetsSidebar_js.bundle.js
__page_editor_plugins_widgets_index_js.bundle.js
__page_editor_prop_types_BackgroundImagePropTypes_js.bundle.js
__page_editor_prop_types_ConfigurationFieldPropTypes_js.bundle.js
__page_editor_prop_types_getEditableItemPropTypes_js.bundle.js
__page_editor_prop_types_getLayoutDataItemPropTypes_js.bundle.js
__page_editor_prop_types_index_js.bundle.js
__page_editor_prop_types_LayoutDataPropTypes_js.bundle.js

And, for example, the wp-inspect of the index entry point shows this:

$ wp-inspect build/node/bundler/webpack/__page_editor_common_index_js.bundle.js 
Webpack entry [ '__page_editor_common_index_js' ] :
    Implementations:
        ./build/node/bundler/generated/__page_editor_common_index_js.js
        ./src/main/resources/META-INF/resources/page_editor/common/index.js
    Dependencies:
        ./build/node/bundler/generated/__page_editor_common_index_js.js
        runtime
        __page_editor_common_components_SidebarPanelHeader_js~__page_editor_common_index_js~__page_editor_pl~80927b30
        __page_editor_common_components_Collapse_js~__page_editor_common_index_js
        __page_editor_common_components_SearchForm_js~__page_editor_common_index_js

So, it looks like webpack knows how to do a good work of optimization.

izaera commented 4 years ago

I suppose this shows that the export everything approach is feasible.

However we now need to:

  1. Decide if we want to continue with this approach.
  2. If we continue, we must make changes to the bundler to make it load the needed files in the needed order (instead of blindly loading vendor.js for every entry point). This looks somewhat costly, but feasible, because it's what the HtmlWebpackPlugin does.
  3. Decide if we let the users drive the optimization (I would say yes).
  4. Decide if having so many chunks doesn't go too much against debugging.

If point 3 is decided, we can alleviate point 4 because the user will always be able to change the optimization configuration to ease debugging (much in the same way they do when they use webpack alone, I guess).

izaera commented 4 years ago

We should also look at the sizes of the output directories in the extremes of the scale to know how much overhead in the form of copy-paste is created when splitting too aggresively. Maybe the wp-inspect script can be modified to look at the directory as a whole and report duplication inside the bundles.

Another thing that comes to my mind is that we have a "problem" because we go against the assumptions made by webpack:

I mean, webpack assumes that each entry point will be loaded in its own HTML page, so it doesn't care about copy-paste in the same way we do, because if two different chunks that are loaded in two different pages (exclusively) share code nothing happens (apart from using hard disk and bandwidth the first time it's downloaded to the cache).

But in our case, because the AMD loader will hold those chunks in memory, every copy-paste counts against us. So we may want to avoid copy-paste due to splitting as much as we can if we want a decent performance.

jbalsas commented 3 years ago

Doing some autumn cleaning as we move this project to https://github.com/liferay/liferay-frontend-projects#js-toolkit

We'll be curating these and creating new ones mostly from scratch to have a better sense of where we want to go.