-
Notifications
You must be signed in to change notification settings - Fork 54
6.0.0 Preparing for breaking changes
Breaking changes are coming in 6.0. They will impact how components/sub-components/functions/hooks are exposed.
- use
@talend/scripts-core
to ease the process. - if your app don't import from specific nested files directly, this will go smoothly.
- otherwise, you will have to get those entities from their main component (ex:
List.hooks
,List.Manager
).
@talend/ui
has been growing a lot since the last 3 years. We plan to introduce some major breaking changes to clean up what we expose and how we expose the components and utility functions.
The goal is not just to clean things, those changes are needed to bring our library to the next level:
⭐ Serving it via CDN ⭐
To understand what we target we need to answer to those questions:
- how do we build the packages ?
- what are exposed ?
- how do we use @talend/ui in the apps ?
We use babel to compile the code to be supported in all the target browser. That allows us to use new ES features.
This step keeps the folder hierarchy.
Source folder hierarchy | Compiled folder hierarchy |
---|---|
/src |_ /AboutDialog |_ AboutDialog.scss |_ AboutDialog.component.js |_ AboutDialog.test.js |_ AboutDialogTable.component.js |_ AboutModal.stories.js |_ index.js |_ /ActionBar |_ /ActionIntercom |
/lib |_ /AboutDialog |_ AboutDialog.scss |_ AboutDialog.component.js |_ AboutDialog.component.js.map |_ AboutDialogTable.component.js |_ AboutDialogTable.component.js.map |_ index.js |_ index.js.map |_ /ActionBar |_ /ActionIntercom |
We have an index.js
at the root of the app that exposes almost all the components, some constants, some functions. That is quite a mess to be honest.
In each folder, we also have an index.js
that exposes the main component as default, and sometimes some sub components, functions, or hooks. The sub components and hooks can be useful when we allow composition for example.
In Talend apps, we usually import components/constants/functions/hooks from folder index
import AboutDialog from '@talend/react-components/lib/AboutDialog`;
import List, { hooks as listHooks } from '@talend/react-components/lib/List/ListComposition';
Importing from /lib/<component_folder>
allows us to tree shake the library, including only the components we use in our app bundle.
But we are in javascript, and every export
from a file, can be imported :/
File | Javascript possible import |
---|---|
/src/index.js | import { List } from '@talend/react-components' |
/src/List/index.js | import List from '@talend/react-components/lib/List' |
/src/List/ListComposition/index.js | import List from '@talend/react-components/lib/List/ListComposition' |
/src/List/ListComposition/index.js | import { hooks } from '@talend/react-components/lib/List/ListComposition' |
/src/List/ListComposition/Manager/hooks/useCollectionSelection.js | import useCollectionSelection from '@talend/react-components/lib/List/ListComposition/Manager/hooks/useCollectionSelection.js' |
ℹ️ There are cases where some apps do some nested imports, and that introduces part of the issues to enable @talend/ui on CDN.
We want to serve @talend/ui
on a CDN. This allows:
- to push some common changes at the same time such as a change of color in a component
- no need to upgrade and release all the apps
- better caching
- to download several bundles in parallel
Of course there are some drawbacks
- no tree-shaking anymore
- we download the whole library
But the parallel download and the caching saves us a bit.
To understand the issue, let's see how we can serve a library on a CDN
When serving a library via CDN, we set 1 file for js, containing the whole library. There is no split.
Some example
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.js"></script>
⚠️ Nested imports don't work anymore because there is no folder hierarchy ! We can only import from index.
We need to expose the main
components directly in src/index.js
.
import { List } from '@talend/react-components'; // this is ok
-import List from '@talend/react-components/lib/List';
+import { List } from '@talend/react-components';
-import List from '@talend/react-components/lib/List/ListComposition';
+import { ListComposition } from '@talend/react-components'; // we need to expose it in index
But we got you covered. We are preparing a babel plugin to change those nested main
components imports into an import from index. As you use @talend/scripts-core
, this will be integrated directly, no need to change those imports manually.
ℹ️ Use
@talend/scripts-core
to support this for almost free
Let's take an example: the ListComposition components.
import ListManager from '@talend/react-components/lib/List/ListComposition/Manager';
import ListToolbar from '@talend/react-components/lib/List/ListComposition/Toolbar';
import VList from '@talend/react-components/lib/List/ListComposition/VList';
function MyList() {
return (
<ListManager id="my-list" collection={simpleCollection}>
<ListToolbar>
{...actions}
</ListToolbar>
<VList>
{..columnDefinitions}
</VList>
</ListManager>
);
}
In List composition, we expose sub components to compose the List, including a toolbar and the real list of data.
A fast way to allow UMD is to expose all the components in the main index.js
. But that would mean
- to rename lots of components to add a context in the name. For example
VList
doesn't fit anymore, we need to enforce the fact that it's used in the list composition. - the
index.js
will expose tons of items.
A better way to do that is to attach all sub components on a main component.
-import ListManager from '@talend/react-components/lib/List/ListComposition/Manager';
-import ListToolbar from '@talend/react-components/lib/List/ListComposition/Toolbar';
-import VList from '@talend/react-components/lib/List/ListComposition/VList';
+import { ListComposition as List } from '@talend/react-components';
-<ListManager>
+<List.Manager>
-<ListToolbar>
+<List.Toolbar>
-<VList>
+<List.VList>
So we keep main components in index.js
, and all sub components are exposed via the main one.
import { ListComposition as List } from '@talend/react-components';
function MyList() {
return (
<List.Manager id="my-list" collection={simpleCollection}>
<List.Toolbar>
{...actions}
</List.Toolbar>
<List.VList>
{..columnDefinitions}
</List.List>
</List.Manager>
);
}
⚠️ This is a breaking change. We will change how sub components are exposed.
Unfortunately, we can't automate this change, and the time spent to do a codemod doesn't worth it. We will have to adapt manually. But luckily, there are not that many of those cases today.
This case is similar to sub components. Utility functions and hooks are created for a component need, we will attach them to the main component.
-import useCollectionSelection from '@talend/react-components/lib/List/ListComposition/Manager/hooks/useCollectionSelection.hook';
+import { ListComposition as List } from '@talend/react-components`;
+const { useCollectionSelection } = List.hooks;
⚠️ This is a breaking change. We will change how utility functions and hooks are exposed.
Breaking changes are coming in 6.0. They will impact how components/sub-components/functions/hooks are exposed.
- use
@talend/scripts-core
to ease the process. - if your app don't import from specific nested files directly, this will go smoothly.
- otherwise, you will have to get those entities from their main component (ex:
List.hooks
,List.Manager
).