Skip to content

Commit

Permalink
refactor: optimize bundle size with isolated modules (#1839)
Browse files Browse the repository at this point in the history
Co-authored-by: saurabhdaware <[email protected]>
  • Loading branch information
anuraghazra and saurabhdaware authored Dec 13, 2023
1 parent 85c8634 commit 40e51a5
Show file tree
Hide file tree
Showing 136 changed files with 5,723 additions and 2,753 deletions.
50 changes: 50 additions & 0 deletions .changeset/weak-adults-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
"@razorpay/blade": minor
---

feat(blade): optimize bundle size with isolated modules & enable codesplitting

**Migration:**

## Jest

**transformIgnorePatterns:**

In your jest config's [`transformIgnorePatterns`](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring) add `@table-library` so that it gets transpiled by jest.

```diff
// jest.config.js
transformIgnorePatterns: [
- '/node_modules/(?!(@razorpay/blade|commander)|uuid|@babel/runtime/)',
+ '/node_modules/(?!(@razorpay/blade|commander)|uuid|@babel/runtime|@table-library/)',
],
```

**moduleNameMapper:**

In your jest config's [`moduleNameMapper`](https://jestjs.io/docs/configuration#modulenamemapper-objectstring-string--arraystring), you can remove the aliased blade modules:

This is present in [x](https://github.com/razorpay/x/blob/master/jest.config.js#L49-L51), [frontend-website](https://github.com/razorpay/frontend-website/blob/master/jest.config.js#L14-L16) & [admin-dashboard](https://github.com/razorpay/admin-dashboard/blob/master/jest.config.js#L14-L16) repo.

```diff
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
- '@razorpay/blade/tokens': '@razorpay/blade/build/tokens/index.development.web.js',
- '@razorpay/blade/utils': '@razorpay/blade/build/utils/index.development.web.js',
- '@razorpay/blade/components': '@razorpay/blade/build/components/index.development.web.js',
},
```

## Third Party Libs

While this change is not a breaking change, but we've made a few changes in how the dependencies are handled by blade internally.

- Web:

In web, we've marked all the dependencies as `external`, that means you don't need to install the peer dependencies manually,
If you have `@floating-ui/react` in your `package.json` you can safely remove it, yarn/npm will automatically install the appropriate version for you.

- Native:

In native, we've marked all the dependencies as peerDependencies, so that web consumers doesn't have to install them + ensures there are no mismatches between blade vs consumer dependencies.
Please refer to the [installation guide](https://blade.razorpay.com/?path=/docs/guides-installation--page#-add-blade-to-your-application)https://blade.razorpay.com/?path=/docs/guides-installation--page#-add-blade-to-your-application for more details.
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ coverage
**/storybook-site
**/build
packages/blade/components.js
packages/blade/components.native.js
packages/blade/components.d.ts
packages/blade/tokens.js
packages/blade/tokens.native.js
packages/blade/tokens.d.ts
packages/blade/utils.js
packages/blade/utils.native.js
packages/blade/utils.d.ts


Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/blade-validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ jobs:
- name: Run TypeScript Checks
run: yarn typecheck
working-directory: packages/blade
- name: Check Bundle Size
run: yarn bundlemon
working-directory: packages/blade
env:
CI_COMMIT_SHA: ${{github.event.pull_request.head.sha || github.sha}}
- name: Check Tree Shaking
run: yarn size-limit
working-directory: packages/blade
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ coverage
**/storybook-site
**/build
packages/blade/components.js
packages/blade/components.native.js
packages/blade/components.d.ts
packages/blade/tokens.js
packages/blade/tokens.native.js
packages/blade/tokens.d.ts
packages/blade/utils.js
packages/blade/utils.native.js
packages/blade/utils.d.ts

# misc
Expand Down
18 changes: 16 additions & 2 deletions packages/blade/.storybook/react-native/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,23 @@ const getStories = () => {
'./src/components/SkipNav/SkipNav.stories.tsx': require('../../src/components/SkipNav/SkipNav.stories.tsx'),
'./src/components/Spinner/BaseSpinner/BaseSpinner.stories.tsx': require('../../src/components/Spinner/BaseSpinner/BaseSpinner.stories.tsx'),
'./src/components/Spinner/Spinner/Spinner.stories.tsx': require('../../src/components/Spinner/Spinner/Spinner.stories.tsx'),
'./src/components/SpotlightPopoverTour/Tour.stories.tsx': require('../../src/components/SpotlightPopoverTour/Tour.stories.tsx'),
'./src/components/SpotlightPopoverTour/docs/Tour.stories.tsx': require('../../src/components/SpotlightPopoverTour/docs/Tour.stories.tsx'),
'./src/components/SpotlightPopoverTour/docs/TourDocs.stories.tsx': require('../../src/components/SpotlightPopoverTour/docs/TourDocs.stories.tsx'),
'./src/components/Switch/Switch.stories.tsx': require('../../src/components/Switch/Switch.stories.tsx'),
'./src/components/Table/docs/Table.stories.tsx': require('../../src/components/Table/docs/Table.stories.tsx'),
'./src/components/Table/docs/APIStories/TableAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableBodyAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableBodyAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableCellAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableCellAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableFooterAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableFooterAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableFooterCellAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableFooterCellAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableFooterRowAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableFooterRowAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableHeaderAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableHeaderAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableHeaderCellAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableHeaderCellAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableHeaderRowAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableHeaderRowAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TablePaginationAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TablePaginationAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableRowAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableRowAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableToolbarActionsAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableToolbarActionsAPI.stories.tsx'),
'./src/components/Table/docs/APIStories/TableToolbarAPI.stories.tsx': require('../../src/components/Table/docs/APIStories/TableToolbarAPI.stories.tsx'),
'./src/components/Table/docs/BasicTable.stories.tsx': require('../../src/components/Table/docs/BasicTable.stories.tsx'),
'./src/components/Table/docs/TableExamples.stories.tsx': require('../../src/components/Table/docs/TableExamples.stories.tsx'),
'./src/components/Tabs/Tabs.stories.tsx': require('../../src/components/Tabs/Tabs.stories.tsx'),
'./src/components/Tag/Tag.stories.tsx': require('../../src/components/Tag/Tag.stories.tsx'),
Expand Down
68 changes: 68 additions & 0 deletions packages/blade/dependencies-external-plugin.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Modified from: https://github.com/pmowrer/rollup-plugin-peer-deps-external/blob/master/src/index.js#L3
// eslint-disable-next-line import/no-extraneous-dependencies
import { either } from 'ramda';
const isFunction = (fn) => typeof fn === 'function';

/**
* Utility function mapping a Rollup config's `external` option into a function.
* In Rollup, the `external` config option can be provided as "either a function
* that takes an id and returns true (external) or false (not external), or an
* Array of module IDs, or regular expressions to match module IDs, that should
* remain external to the bundle. Can also be just a single ID or regular
* expression." (https://rollupjs.org/guide/en/#external)
*
* An `external` configuration in string/regexp/array format can be represented
* in the function format, but not vice-versa. This utility accepts either format
* and returns the function representation such that we can easily retain the user's
* configuration while simultaneously appending peer dependencies to it.
*
* @param {String|RegExp|Array|Function} external The `external` property from Rollup's config.
* @returns {Function} Function equivalent of the passed in `external`.
*/
function externalToFn(external) {
if (isFunction(external)) {
return external;
} else if (typeof external === 'string') {
return (id) => external === id;
} else if (external instanceof RegExp) {
return (id) => external.test(id);
} else if (Array.isArray(external)) {
return (id) =>
external.some((module) => (module instanceof RegExp ? module.test(id) : module === id));
}
// Per the rollup docs, `undefined` isn't a valid value for the `external` option,
// but it has been reported to have been passed in configs starting with 2.11.0.
// It's unclear why it's happening so we'll support it for now:
// https://github.com/pmowrer/rollup-plugin-peer-deps-external/issues/29
else if (typeof external === 'undefined') {
return () => false;
} else {
throw new Error(
`rollup-plugin-peer-deps-external: 'external' option must be a function or an array.`,
);
}
}

const moduleRegExp = (module) => new RegExp(`^${module}(\\/\.+)*$`);

function getModulesMatcher(modulesNames) {
const regexps = modulesNames.map(moduleRegExp);
return (id) => regexps.some((regexp) => regexp.test(id));
}
function depsExternalPlugin({ externalDependencies } = {}) {
return {
name: 'deps-external',
options: (opts) => {
opts.external = either(
// Retain existing `external` config
externalToFn(opts.external),
getModulesMatcher(externalDependencies),
);

return opts;
},
};
}

export { depsExternalPlugin };
44 changes: 28 additions & 16 deletions packages/blade/docs/guides/Installation.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,40 @@ Blade has a peer dependency on a few libraries, you can skip adding it if you al
> **Note**
>
> Currently, blade only supports styled-components v5 only
- `@floating-ui/react`
```shell
yarn add @razorpay/blade [email protected] @floating-ui/react
yarn add @razorpay/blade [email protected]
```
2. Follow [this guide](#-install-fonts) to install the fonts.

3. For **React Native** projects you need to do additional setup for the peer dependencies:

- `react-native-reanimated`
- Follow [this guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation) to install it on Android & iOS which is required by Blade.
- `react-native-svg`
- Follow [this guide](https://github.com/react-native-svg/react-native-svg#with-react-native-cli) to install it on Android & iOS which is required by Blade.
- `react-native-gesture-handler`
- Follow [this guide](https://docs.swmansion.com/react-native-gesture-handler/docs/installation) to install it, note that you don't need to add `<GestureHandlerRootView style={{ flex: 1 }}>` again on the root because BladeProvider already adds that out of the box.
- `@gorhom/bottom-sheet`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@gorhom/portal`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@floating-ui/react-native`
- Add this as peer dependency, no need to do additional setup.
- `react-native-pager-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).
```shell
yarn add @floating-ui/[email protected] [email protected] [email protected] [email protected] [email protected] [email protected] @gorhom/[email protected] @gorhom/[email protected]
```

- `react-native-reanimated`
- Follow [this guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation) to install it on Android & iOS which is required by Blade.
- `react-native-svg`
- Follow [this guide](https://github.com/react-native-svg/react-native-svg#with-react-native-cli) to install it on Android & iOS which is required by Blade.
- `react-native-gesture-handler`
- Follow [this guide](https://docs.swmansion.com/react-native-gesture-handler/docs/installation) to install it, note that you don't need to add `<GestureHandlerRootView style={{ flex: 1 }}>` again on the root because BladeProvider already adds that out of the box.
- `@gorhom/bottom-sheet`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@gorhom/portal`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@floating-ui/react-native`
- Add this as peer dependency, no need to do additional setup.
- `react-native-tab-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).
- `react-native-pager-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).

And finally run `pod install` command so that blade's RN dependencies are linked to your project:

```shell
cd ios && pod install
```

## 🔜 Add blade libraries to your Figma project

Expand Down
4 changes: 2 additions & 2 deletions packages/blade/docs/tokens/Border.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meta, DocsContainer } from '@storybook/addon-docs';
import { BladeProvider } from '../../src/components';
import { makeBorderSize, useTheme } from '../../src/utils';
import { BladeProvider, useTheme } from '../../src/components';
import { makeBorderSize } from '../../src/utils';
import { paymentTheme, bankingTheme } from '../../src/tokens';

<Meta
Expand Down
Loading

0 comments on commit 40e51a5

Please sign in to comment.