Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

De-duplicate Webpack build, especially components/ #929

Merged
merged 10 commits into from
May 30, 2017
Merged

Conversation

nylen
Copy link
Member

@nylen nylen commented May 29, 2017

While looking at #926 I noticed that we are probably duplicating some code in the components/ directory across built files. For example, we import IconButton in both editor/header/tools/preview-button.js and blocks/editable/format-toolbar.js.

If we split components/ out into a separate build + entry point, we should be able to resolve this issue, and also make our common components available via wp.components, which seems good for reusability.

This PR is an attempt at doing this, but it's not working for some reason. Here are the build sizes before this PR:

$ ls -la */build/*.js
271232 blocks/build/index.js
  3119 date/build/index.js
466975 editor/build/index.js
 14447 element/build/index.js
 17481 i18n/build/index.js

and after:

$ ls -la */build/*.js
271230 blocks/build/index.js
118012 components/build/index.js
  3119 date/build/index.js
467031 editor/build/index.js
 14389 element/build/index.js
 17481 i18n/build/index.js

@nylen nylen added [Type] Build Tooling Issues or PRs related to build tooling [Status] In Progress Tracking issues with work in progress labels May 29, 2017
`component` depends on `element`. :(
@BE-Webdesign
Copy link
Contributor

Looks good to me. Will we also need to go through the files and change where modules are being imported from? Or is webpack smart enough to not duplicate once a build is created for that directory? Here is the current list to illustrate what I mean.

gutenberg\blocks\block-controls\index.js
9:import Toolbar from 'components/toolbar';

gutenberg\blocks\editable\format-toolbar.js
4:import IconButton from 'components/icon-button';
5:import Toolbar from 'components/toolbar';

gutenberg\blocks\editable\index.js
13:import Toolbar from 'components/toolbar';

gutenberg\blocks\library\button\index.js
4:import IconButton from 'components/icon-button';

gutenberg\blocks\library\embed\index.js
4:import Button from 'components/button';
5:import Placeholder from 'components/placeholder';

gutenberg\blocks\library\image\index.js
4:import Placeholder from 'components/placeholder';

gutenberg\blocks\media-upload-button\index.js
6:import Button from 'components/button';

gutenberg\components\panel\body.js
5:import IconButton from 'components/icon-button';

gutenberg\components\placeholder\index.js
10:import Dashicon from 'components/dashicon';

gutenberg\editor\block-mover\index.js
9:import IconButton from 'components/icon-button';

gutenberg\editor\block-switcher\index.js
11:import IconButton from 'components/icon-button';
12:import Dashicon from 'components/dashicon';

gutenberg\editor\header\mode-switcher\index.js
9:import Dashicon from 'components/dashicon';

gutenberg\editor\header\saved-state\index.js
10:import Dashicon from 'components/dashicon';

gutenberg\editor\header\tools\index.js
10:import IconButton from 'components/icon-button';

gutenberg\editor\header\tools\preview-button.js
9:import IconButton from 'components/icon-button';

gutenberg\editor\header\tools\publish-button.js
9:import Button from 'components/button';

gutenberg\editor\inserter\index.js
10:import IconButton from 'components/icon-button';

gutenberg\editor\inserter\menu.js
11:import Dashicon from 'components/dashicon';
12:import withFocusReturn from 'components/higher-order/with-focus-return';

gutenberg\editor\modes\visual-editor\block.js
14:import Toolbar from 'components/toolbar';

gutenberg\editor\sidebar\block-inspector\index.js
9:import Panel from 'components/panel';
10:import PanelHeader from 'components/panel/header';
11:import PanelBody from 'components/panel/body';

gutenberg\editor\sidebar\discussion-panel\index.js
11:import PanelBody from 'components/panel/body';
12:import FormToggle from 'components/form-toggle';

gutenberg\editor\sidebar\featured-image\index.js
11:import Button from 'components/button';
12:import PanelBody from 'components/panel/body';
14:import Spinner from 'components/spinner';

gutenberg\editor\sidebar\index.js
9:import withFocusReturn from 'components/higher-order/with-focus-return';

gutenberg\editor\sidebar\post-excerpt\index.js
10:import PanelBody from 'components/panel/body';

gutenberg\editor\sidebar\post-schedule\clock.js
5:import Button from 'components/button';

gutenberg\editor\sidebar\post-settings\index.js
10:import Panel from 'components/panel';
11:import PanelHeader from 'components/panel/header';
12:import IconButton from 'components/icon-button';

gutenberg\editor\sidebar\post-status\index.js
11:import PanelBody from 'components/panel/body';
12:import FormToggle from 'components/form-toggle';

gutenberg\editor\sidebar\post-trash\index.js
10:import Button from 'components/button';
11:import Dashicon from 'components/dashicon';

@nylen
Copy link
Member Author

nylen commented May 30, 2017

Or is webpack smart enough to not duplicate once a build is created for that directory?

This is the part that's not working yet - I would expect to see the 118kb file for components/build/index.js, and then I would expect to see slightly more than this 118kb (due to existing duplication) moved out of blocks/build/index.js and editor/build/index.js.

I suspect something is still missing in the webpack config.

@nylen
Copy link
Member Author

nylen commented May 30, 2017

Before this PR there's actually a lot of duplication in the built files. Multiple copies of Dashicon, for example. The latest commits improve things somewhat - here are the new build sizes:

$ ls -la */build/*.js
253181 blocks/build/index.js
 96260 components/build/index.js
  3119 date/build/index.js
334667 editor/build/index.js
 14554 element/build/index.js
 17483 i18n/build/index.js

However, there is still a lot of duplication - IconButton and Dashicon are each present in the blocks, editor, and components builds. To achieve full separation between our built files, we will have to make further changes:

- import IconButton from 'components/icon-button';
+ import { IconButton } from 'components';

nylen added 4 commits May 29, 2017 23:40
- Fix entry point order to match actual dependencies
- Fix externals (`wp.*` externals not needed)
@nylen nylen changed the title Build components/ directory separately De-duplicate components/ and other parts of Webpack build May 30, 2017
@nylen nylen changed the title De-duplicate components/ and other parts of Webpack build De-duplicate Webpack build, especially components/ May 30, 2017
@nylen
Copy link
Member Author

nylen commented May 30, 2017

This PR should be ready for review now. It shaves 200 KB off of the production build size by adding a new components/build/index.js output file and then eliminating a lot of duplication across the various files built by Webpack.

It works by registering each of our top-level entry points like components as an external library using the Webpack externals option. Behind the scenes, then, Webpack will transform import { thing } from 'components' into something that translates to wp.components.thing. Previously, all imports from e.g. components were being included in each output file.

I saw #901 (comment) after I already started restructuring imports in this way. The one difference is that everything should be imported from components directly, instead of subdirectories like components/higher-order.

Current sizes:

$ ls -la */build/*.js
179431 blocks/build/index.js
 96343 components/build/index.js
  3119 date/build/index.js
258059 editor/build/index.js
 14550 element/build/index.js
 17483 i18n/build/index.js

Final statistics:

773254  Build size on `master`
568985  Build size on this branch
204269  Savings (26% of original size)

@nylen nylen removed the [Status] In Progress Tracking issues with work in progress label May 30, 2017
export { default as Spinner } from './spinner';
export { default as Toolbar } from './toolbar';

export { default as withFocusReturn } from './higher-order/with-focus-return';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should export this in the root module. I'm thinking we should create a index.js in the ./higher-order/ folder to be able to import those as import { withFocusReturn } from 'components/higher-order';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just saw your comment #929 (comment)

I still think we should make a distinction between importing components and HoC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we make this work like wp.components.something behind the scenes?

I think this could be solved separately, in any case.

Copy link
Contributor

@BE-Webdesign BE-Webdesign left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice Work! Verified that the build size is significantly smaller. LGTM, any issues can be cycled back to in another PR I think as this resolves things for the current structure.

@nylen nylen mentioned this pull request May 30, 2017
@nylen
Copy link
Member Author

nylen commented May 30, 2017

I've created #941 to discuss next steps.

@nylen nylen merged commit ccf8728 into master May 30, 2017
@ellatrix
Copy link
Member

I think this broke master. There's an error if you open the inspector.

@youknowriad
Copy link
Contributor

Confirmed this broke a lot of components. I fixed this in a branch 17741f4 but we should probably fix this separately

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Build Tooling Issues or PRs related to build tooling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants