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

Add bundling (rollup) #34

Merged
merged 27 commits into from
Sep 10, 2018
Merged

Add bundling (rollup) #34

merged 27 commits into from
Sep 10, 2018

Conversation

dferber90
Copy link
Contributor

@dferber90 dferber90 commented Sep 7, 2018

Attempt número dos (after #30 failed to produce a treeshakeable build).

So far we were shipping untranspiled/unbundled code. This meant that all consumers of UI-Kit had to have the right webpack loaders in place in order to consume UI-Kit, which is quite bad of course. If we were to update any of our loaders, all consumers would have had to update them as well.

This PR makes it so that the UI-Kit ships as a standalone library, which can be consumed by any project which has the peerDependencies like react and react-dom of UI-Kit installed as regular dependencies.

Usage

The available commands were moved around a bit. The main updates are:

  • yarn start: an alias for yarn storybook:start
  • yarn build: New command to build the ui-kit for production to dist
  • yarn storybook:start: Starts the storybook locally
  • yarn storybook:build: Builds storybook for production

Consumers

Consumers of UI-Kit can use it by importing components from the main export:

import { PrimaryButton } from '@commercetools-frontend/ui-kit'

The main export will serve all components.

Publishing

The build gets put into the dist folder. As we don't want to force consumers to use ugly imports containing dist like @commercetools-frontend/ui-kit/dist/materials, we are doing a workaround to prevent this.

We copy all files which we want to be included in the npm module to the dist folder. Currently, this is the README.md, LICENSE and the package.json. We later need to publish from the dist folder.

You can try this out by running yarn build; cd dist; yarn pack (yarn pack is like yarn publish, except that it doesn't publish the created module). Then inspect the contents of the generated .tar.gz file which represent the module that would be published on npm.

Copying of package.json to dist and publishing from there lets consumers avoid the dist in imports as the folder is no longer part of the module.

package.json getting copied to dist is also why the main field in package.js contains ui-kit.cjs.js instead of dist/ui-kit.cjs.js.

This preparation should make it fairly easy to set up the release script in #2.

main and module

The package.json has two fields, "main": "ui-kit.cjs.js" and "module": "ui-kit.esm.js". In case consumers of ui-kit use a bundler which supports the module field, then the consumer will benefit from treeshaking when building. This means that only the used components will end up in the final application build.

Consumers using the main field will load the whole UI Kit which is quite big. This is not recommended.

Uglify

The UI Kit is served as-is. Uglifying is the responsibility of the consumer of the UI Kit.

CSS

We are not creating an external CSS file at the moment. All CSS (global and modular) required to run UI-Kit is packed into the index.esm.js file. Unfortunately the CSS does not benefit from treeshaking yet. So even when a component is not being used, its styles will still get included into the parent, and injected into the document head.

See egoist/rollup-plugin-postcss#98 for more.

We can try to tackle this separately later. I have a PoC where treeshaking CSS is possible.

SVG (and other assets)

We convert the Icons to React Components while exposing regular SVG and PNG images from materials as plain assets.

Messages

We export the messages from index.js as en, de and es for now.
They can also be used through import { en, de, es } from 'ui-kit/i18n/messages'.

This setup is not final and serves mostly to avoid breaking changes there for now.

proxy exports copying

Some consumers "reach into" ui-kit to import files like this:

import PrimaryButton from 'ui-kit/buttons/primary-button'

This is deprecated and should not be used anymore.

We want to avoid breaking changes for now, thus we have to keep supporting consumers which reach into UI-Kit. We do this by recreating the previous folder structure by copying proxy-exports into the final dist folder. The copied files merely re-export from the generated index.esm.js files.

We will remove this once the consumers have been updated.

circular dependency warnings after build

Right now we attempt to bundle react-virtualized and styled-components into the main bundle. These both result in some circular dependency warnings when bundling. We plan to get rid of both of these libraries soon, so we did not spend time to attempt to fix this.

thread-loader

I did some experimentation and it turns out that the build time is 20s faster on the initial build, and 4s faster on following builds (with filled cache) when not using thread-loader, so I removed it. This is an unrelated change and concerns the Webpack setup only.

Todo

  • adapt netlify to execute the right command

Possible Future Improvements:

  • verify treeshaking works (CSS doesn't work for sure)
  • enable treeshaking of CSS
  • move Components (Contraints, Spacings) out of materials

💐And finally, a thanks a ton to @montezume for setting the branch up in the first place, and for pairing on this with me!

This is what the final bundle published to npm would look like: ui-kit.zip

Closes #7

// For normal svg files (not icons) we should load the file normally
// and simply use it as a `<img src/>`.
{
test: function testForNormalSvgFiles(fileName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

we weren't actually bundling any "normal" SVG files, so removed this for readability.

Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: can we keep it there in case we need it in the future? I don't mind though to remove it...

Copy link
Contributor

@montezume montezume Sep 10, 2018

Choose a reason for hiding this comment

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

If you want I can re-add this, what I like about removing it is that it will make really apparent if someone adds SVG and PNG's because they will need to modify the webpack config

Copy link
Member

Choose a reason for hiding this comment

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

Sure, I don't mind. We can keep it removed for now

// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
test: /\.png$/,
Copy link
Contributor

Choose a reason for hiding this comment

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

again unused, so removing to make the config easier to read.

package.json Outdated
@@ -89,11 +93,13 @@
"moment-timezone": "0.5.21",
"omit-empty": "0.4.1",
"postcss": "7.0.2",
"postcss-color-mod-function": "2.4.3",
"postcss-import": "12.0.0",
"postcss-color-mod-function": "^2.4.3",
Copy link
Contributor

Choose a reason for hiding this comment

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

ah maybe we should change these and remove the ^

rollup.config.js Outdated
}),
json(),
svg({
include: ['**/*.svg'],
Copy link
Contributor

Choose a reason for hiding this comment

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

ah this can be removed

rollup.config.js Outdated
// We tried all copy plugins of rollup, and couldn't get a single one to
// do this. So, the shell it is!
execute(
'cp -R package.json README.md LICENSE materials proxy-exports/ dist/'
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Woops, had forgotten to copy the materials/images

Copy link
Member

@emmenko emmenko left a comment

Choose a reason for hiding this comment

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

🤩🤩🤩

Fuck**g yeah! 👩‍🎤🎸

// For normal svg files (not icons) we should load the file normally
// and simply use it as a `<img src/>`.
{
test: function testForNormalSvgFiles(fileName) {
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: can we keep it there in case we need it in the future? I don't mind though to remove it...

i18n/index.js Show resolved Hide resolved
@@ -7,15 +7,18 @@
"publishConfig": {
"access": "public"
},
"main": "src/index.js",
"main": "ui-kit.cjs.js",
"module": "ui-kit.esm.js",
Copy link
Member

Choose a reason for hiding this comment

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

💯

Copy link
Contributor

Choose a reason for hiding this comment

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

In node land ESM modules (if my memory is still correct) can only be supported by the mjs extension. Should we go for the same extension here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I also still wanted to look into the difference of specifying es and esm as the output.

"build": "build-storybook -o .public",
"start": "start-storybook -p 9002",
"prestorybook:start": "node ./scripts/generate-base-colors.js && node ./scripts/generate-base-shadows.js && node ./scripts/generate-colors-for-story.js",
"storybook:build": "build-storybook -o .public",
Copy link
Member

Choose a reason for hiding this comment

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

Cool, I'll push the netlify config file so we can change the build script from there.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

image

package.json Outdated
"start": "start-storybook -p 9002",
"prestorybook:start": "node ./scripts/generate-base-colors.js && node ./scripts/generate-base-shadows.js && node ./scripts/generate-colors-for-story.js",
"storybook:build": "build-storybook -o .public",
"build": "NODE_ENV=production rollup -c",
Copy link
Member

Choose a reason for hiding this comment

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

Niptick: I usually see cross-env being used. Should we add it as well?

@@ -0,0 +1,2 @@
// NOTE: this is a proxy export for backwards compatibility
export { AccessibleButton as default } from '../../ui-kit.esm';
Copy link
Member

Choose a reason for hiding this comment

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

Nice! 💯

@@ -0,0 +1,93 @@
export { AddBoldIcon } from '../ui-kit.esm';
Copy link
Member

Choose a reason for hiding this comment

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

Is this list generated or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We created it manually in hope of all future consumers importing from ui-kit.esm instead.

We hope to be able to remove all these proxy-exports soon. So it didn't feel reasonable to write a script for it if we're going to remove it soon anyways. We want any new icons to be consumed as a named export from the main file.

Copy link
Member

Choose a reason for hiding this comment

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

Sure, I also improved the docs a bit to mention this: 4985d0b

rollup.config.js Show resolved Hide resolved
}),
// this is used for importing both vendor css (from node_modules) and for
// importing our global css which uses tokens that require postcss plugins
// (such as color-mod) to be compiled properly.
Copy link
Member

Choose a reason for hiding this comment

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

👌

rollup.config.js Outdated
}),
// copy static files over
// We tried all copy plugins of rollup, and couldn't get a single one to
// do this. So, the shell it is!
Copy link
Member

Choose a reason for hiding this comment

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

😂

@emmenko
Copy link
Member

emmenko commented Sep 7, 2018

Build is passing now! 🚀

@emmenko
Copy link
Member

emmenko commented Sep 7, 2018

Just had a look at the current main export 😅

Should we maybe group e.g. the icons? import { Icons } from '...'; Icons.AddIcon

export {
  AccessibleButton,
  FlatButton$1 as FlatButton,
  GhostButton,
  IconButton$1 as IconButton,
  LinkButton,
  PrimaryButton,
  secondaryButton as SecondaryButton,
  secondaryIconButton as SecondaryIconButton,
  Collapsible,
  CollapsibleMotion,
  PrimaryActionDropdown,
  Option as PrimaryActionDropdownOption,
  FieldLabel,
  TextField,
  Wrapped as AsyncCreatableSelectInput,
  Wrapped$1 as AsyncSelectInput,
  Enhanced as CreatableSelectInput,
  dateInput as DateInput,
  dateTimeInput as DateTimeInput,
  Wrapped$2 as LocalizedMultilineTextInput,
  LocalizedTextInput,
  MoneyInput,
  Enhanced$1 as MultilineTextInput,
  NumberInput,
  PasswordInput,
  Enhanced$2 as SelectInput,
  TextInput,
  TimeInput$1 as TimeInput,
  Label,
  LoadingSpinner,
  ErrorMessage,
  CollapsiblePanel,
  Label$1 as Stamp,
  Constraints,
  Spacings,
  Table$1 as Table,
  BaseTable,
  Cell as TableCell,
  Tag,
  TimeRangePicker,
  Text,
  withMouseDownState,
  withMouseOverState,
  AddBoldIcon,
  AddIcon,
  AddressBillingIcon,
  AddressShippingIcon,
  AngleDownIcon,
  AngleLeftIcon,
  AngleRightIcon,
  AngleUpIcon,
  ArrowGraphDownIcon,
  ArrowGraphLeftIcon,
  ArrowGraphRightIcon,
  ArrowGraphUpIcon,
  ArrowLeftIcon,
  ArrowLongDownIcon,
  ArrowRightIcon,
  ArrowTriangleDownIcon,
  ArrowTriangleUpIcon,
  ArrowsIcon,
  BackIcon,
  BoxProductIcon,
  BoxIcon,
  BrainIcon,
  CalendarIcon,
  CameraIcon,
  CaretDownIcon,
  CaretUpIcon,
  CartIcon,
  CategoryTreeIcon,
  ChainBrokenIcon,
  ChainIcon,
  CheckActiveIcon,
  CheckInactiveIcon,
  ClipboardIcon,
  ClockIcon,
  CloseBoldIcon,
  CloseIcon,
  CodeViewIcon,
  CoinsIcon,
  ColumnsIcon,
  CopyIcon,
  CubesIcon,
  CustomSettingsIcon,
  CustomViewIcon,
  CustomerFilledIcon,
  CustomerIcon,
  DeleteFilledIcon,
  DeleteIcon,
  DoneIcon,
  DotIcon,
  DownloadIcon,
  DragDropIcon,
  DragIcon,
  EditIcon,
  ErrorIcon,
  ExpandIcon,
  ExportIcon,
  FilterIcon,
  FlagFullfiledIcon,
  FlagIcon,
  FlameIcon,
  GraphIcon,
  GridIcon,
  ImportIcon,
  InfoIcon,
  InformationIcon,
  ListIcon,
  LogoutIcon,
  MailIcon,
  MinimizeIcon,
  NestedViewIcon,
  PagesIcon,
  PinActiveIcon,
  PinIcon,
  ProjectSettingsIcon,
  RefreshIcon,
  RestoreIcon,
  ReturnInfoIcon,
  RevertIcon,
  ReviewIcon,
  SearchIcon,
  SortingIcon,
  SpeedometerIcon,
  SplitIcon,
  SuccessIcon,
  SupportIcon,
  SwitcherIcon,
  TableIcon,
  TagDiscountIcon,
  TagMultiIcon,
  TagIcon,
  VerifiedIcon,
  WarningIcon,
  WorldIcon,
  en$1 as en,
  de$3 as de,
  es$1 as es,
  index$d as Radio,
  Checkbox,
  toggle as Toggle,
};

@dferber90
Copy link
Contributor Author

Sure :) The way we export languages is also pretty bad right now. We are exporting them as import { en, de, es } from 'ui-kit'. We should probably group them as well.

"format:css": "prettier --parser postcss --write '{src}/**/*.css'",
"format:md": "prettier --parser markdown --write '{.github,src,examples}/**/*.md'",
"format:js": "prettier --write '{.storybook,examples,scripts,src}/**/*.js' *.js",
"format:css": "prettier --write --parser css '{.storybook,examples,src}/**/*.css'",
Copy link
Member

Choose a reason for hiding this comment

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

PS: apparently postcss has been deprecated, it's only css now.

image

@emmenko
Copy link
Member

emmenko commented Sep 7, 2018

Oh, the css module proxy exports need to be fixed

Module build failed (from /xxx/node_modules/postcss-loader/src/index.js):
Error: Failed to find '../../src/materials/colors/base-colors.mod.css'
  in [
    /xxx/node_modules/@commercetools-frontend/ui-kit/materials/colors
  ]

@emmenko
Copy link
Member

emmenko commented Sep 7, 2018

We should probably copy the original ones into the dist/materials folder

rollup.config.js Outdated
@@ -101,12 +101,14 @@ export default [
],
},
}),
// copy materials css over. don't even ask :(
Copy link
Contributor

Choose a reason for hiding this comment

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

😢

@montezume
Copy link
Contributor

@emmenko the mod.css exports should pass the MC build now

@emmenko
Copy link
Member

emmenko commented Sep 10, 2018

I'll give it another try, thanks

@emmenko
Copy link
Member

emmenko commented Sep 10, 2018

Tested it locally. Works now!! 🙌

@montezume
Copy link
Contributor

@dferber90 @emmenko ready when you are 🚀

@emmenko
Copy link
Member

emmenko commented Sep 10, 2018

This is now published to npm under the tag rollup-bundle (or version 1.0.0-rollup-bundle)

yarn add @commercetools-frontend/ui-kit@rollup-bundle

@emmenko
Copy link
Member

emmenko commented Sep 10, 2018

There is one small issue with the package.json while releasing...I'll try to push a fix

@@ -0,0 +1,37 @@
// NOTE: this script is only necessary as long as we need to support
// proxy exports for backwards compatibility.
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless we plan on including the png / svg images in materials in the final bundle, we will need to keep this, right?

Copy link
Member

@emmenko emmenko Sep 10, 2018

Choose a reason for hiding this comment

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

Yeah, but then I would put it back to the rollup config once we have settled on our final structure.

);
// 3. Copy only specific fields of the `package.json`
// This is to avoid problems on executing pre/post scripts
// while publishing from inside the `dist` folder.
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool!

@montezume montezume merged commit 26f3df2 into master Sep 10, 2018
@montezume montezume deleted the ml-add-rollups branch September 10, 2018 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ship transpiled code (webpack or rollup)
4 participants