Skip to content

Commit

Permalink
feat(output-target): add output target entries which do not auto defi…
Browse files Browse the repository at this point in the history
…ne custom elements

Since liquid v4.6.0 the includeDefineCustomElements option set to true. With the includeDefineCustomElements option set to true, you don't need to define the custom elements from liquid react yourself. The custom elements get registered with the Custom Elements Registry as soon as imported. We didn't see this as a breaking change, because calling the defineCustomElements helper method manually would not break anything, even if the elements were already defined. However, things get tricky, when bundling liquid components into another library:
With the includeDefineCustomElements option set to true, the react.js and vue.js files within liquid import the defineCustomElements helper and execute it. The defineCustomElements helper imports the bootstrapLazy helper which in turn includes dynamic import statements for all components. Now, a bundler cannot know which component will be lazy loaded eventually, so it includes all components as chunks into the bundle. The app that consumes the library can load only what's needed, but the bundle is still unnecessary big, including all Liquid components, even if not used.
In order to solve this issue, we add additional entry points to the output targets, which do not include the defineCustomElements helper utility. This allows to manually register custom elements on a as-needed basis, and fixes issues with the bundling, because dynamic imports are not used in the code.

Resolves #700
  • Loading branch information
borisdiakur committed May 17, 2023
1 parent 13a993f commit 6077647
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 52 deletions.
2 changes: 1 addition & 1 deletion config/tsconfig.react.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"jsxFactory": "React.createElement",
"outDir": "../dist"
},
"include": ["../out/react.ts"],
"include": ["../out/react.ts", "../out/react-define-excluded.ts"],
"exclude": [
"../node_modules",
"../bin",
Expand Down
2 changes: 1 addition & 1 deletion config/tsconfig.vue.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"declaration": true,
"outDir": "../dist"
},
"include": ["../out/vue.ts"],
"include": ["../out/vue.ts", "../out/vue-define-excluded.ts"],
"exclude": [
"../node_modules",
"../bin",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
"build:patch_loader": "ts-node scripts/patchLoader.ts",
"build:stencil:components": "stencil build --config=stencil.config.ts && shx mv tmp/web-components.html-data.json dist/web-components.html-data.json && shx rm -r tmp",
"build:stencil:docs": "stencil build --config=config/stencil.config.docs.ts",
"build:stencil:react": "ts-node scripts/patchReactOutput.ts && tsc -p config/tsconfig.react.json && (shx rm out/react.ts & shx rm -r out/react-component-lib)",
"build:stencil:vue": "ts-node scripts/patchVueOutput.ts && tsc -p config/tsconfig.vue.json && (shx rm out/vue.ts & shx rm -r out/vue-component-lib)",
"build:stencil:react": "ts-node scripts/patchOutput.ts react && tsc -p config/tsconfig.react.json && (shx rm out/react.ts & shx rm out/react-define-excluded.ts & shx rm -r out/react-component-lib)",
"build:stencil:vue": "ts-node scripts/patchOutput.ts vue && tsc -p config/tsconfig.vue.json && (shx rm out/vue.ts & shx rm out/vue-define-excluded.ts & shx rm -r out/vue-component-lib)",
"build:styles": "run-s build:styles:liquid:globals build:styles:liquid:globals_no_fonts build:styles:liquid:components",
"build:styles:liquid:components": "postcss src/liquid/components/*/*.css src/liquid/components/*/*/*.css --config=config/postcss.config.cjs --no-map -d dist/css/ && trash dist/css/liquid.css 'dist/css/*.shadow.css' && bash scripts/concatStyles.sh",
"build:styles:liquid:globals": "postcss src/liquid/global/styles/global.css --config=config/postcss.config.cjs --no-map -o dist/css/liquid.global.css",
Expand Down
35 changes: 35 additions & 0 deletions scripts/patchOutput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { readFile, writeFile } = require('fs').promises
const outputTarget = process.argv[2]

;(async () => {
const data = await readFile(`./out/${outputTarget}.ts`, 'utf8')

const defineIncluded = data
.replace(
"import type { JSX } from '../dist/components'",
"import type { JSX } from '../dist/types/components'"
)
.replace(
"import { defineCustomElements } from '../dist/components/dist/loader/index.js';",
"import { defineCustomElements } from '../dist/loader/index.es2017.js';"
)

const defineExcluded = data
.replace(
"import type { JSX } from '../dist/components'",
"import type { JSX } from '../dist/types/components'"
)
.split('\n')
.filter((line) => !line.includes('defineCustomElements'))
.join('\n')

await Promise.all([
writeFile(`./out/${outputTarget}.ts`, defineIncluded, 'utf8'),
writeFile(
`./out/${outputTarget}-define-excluded.ts`,
defineExcluded,
'utf8'
),
])
})()
23 changes: 0 additions & 23 deletions scripts/patchReactOutput.ts

This file was deleted.

23 changes: 0 additions & 23 deletions scripts/patchVueOutput.ts

This file was deleted.

43 changes: 42 additions & 1 deletion src/docs/pages/introduction/getting-started/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import '@emdgroup-liquid/liquid/dist/css/liquid.global.css'

When adding Liquid Oxygen components to a React project, it is crucial to use the React bindings. All components are imported from `@emdgroup-liquid/liquid/dist/react`. The bindings significantly improve JSX compatibility and your developer experience.

Let's have a look at how to add a [LdButton](components/ld-button/) to your project. This examnple also includes a [LdIcon](components/ld-icon/) as it helps you to check if Liquid Oxygen assets are loaded correctly.
Let's have a look at how to add a [LdButton](components/ld-button/) to your project. This example also includes a [LdIcon](components/ld-icon/) as it helps you to check if Liquid Oxygen assets are loaded correctly.

```tsx
// SampleComponent.tsx
Expand All @@ -81,6 +81,47 @@ export function SampleComponent() {

When you put this component on a page, you should see a blue button with the text "Click me!" and a lightning bolt icon.

### Manually defining custom elements

When you look at the example above you may notice that we didn't have to define any custom elements anywhere. This is because the React output target includes the define custom elements logic and all custom elements get registered with the Custom Elements Registry as soon as imported (the [Stencil `includeDefineCustomElements` option](https://stenciljs.com/docs/react#includedefinecustomelements) is set to `true`).

In some cases this convenience feature is not desireable, such as when bundling Liquid Oxygen components within your own library, or when you want to have more control over when your custom elements get registered. For this reason Liquid Oxygen exposes a React output target entry which does __not__ include the `defineCustomElements` utility.

Here is how you would implement the example above, using the React output target, that doesn not include the `defineCustomElements` helper method.

```tsx
// SampleComponent.tsx
import { LdButton, LdIcon } from '@emdgroup-liquid/liquid/dist/react-define-excluded'

export function SampleComponent() {
return (
<LdButton>
Click me!
<LdIcon name="energy" />
</LdButton>
)
}
```

Now you can register the components manually in two ways.

1. You can use the `defineCustomElements` utility.

```tsx
import { defineCustomElements } from '@emdgroup-liquid/liquid/dist/loader'
defineCustomElements()
```

2. You can register each element individually.

```tsx
import { LdButton as LdButtonCE } from '@emdgroup-liquid/liquid/dist/components/ld-button'
import { LdIcon as LdIconCE } from "@emdgroup-liquid/liquid/dist/components/ld-icon"

customElements.get('ld-button') || customElements.define('ld-button', LdButtonCE)
customElements.get('ld-icon') || customElements.define('ld-icon', LdIconCE)
```

### Events

Liquid Oxygen components aim to work similarly to native HTML elements as much as possible. In most cases, you can expect the same events and behavior from a Liquid Oxygen component and its native equivalent. Custom events are documented on the respective component pages.
Expand Down
43 changes: 42 additions & 1 deletion src/docs/pages/introduction/getting-started/vue.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Add the following code to your `App.vue` file (or any similar file which is load

When adding Liquid Oxygen components to a Vue project, it is crucial to use the Vue bindings. All components are imported from `@emdgroup-liquid/liquid/dist/vue`. The bindings significantly improve Vue compatibility and your developer experience.

Let's have a look at how to add a [LdButton](components/ld-button/) to your project. This examnple also includes a [LdIcon](components/ld-icon/) as it helps you to check if Liquid Oxygen assets are loaded correctly.
Let's have a look at how to add a [LdButton](components/ld-button/) to your project. This example also includes a [LdIcon](components/ld-icon/) as it helps you to check if Liquid Oxygen assets are loaded correctly.

```html
<!-- SampleComponent.vue -->
Expand All @@ -71,6 +71,47 @@ Let's have a look at how to add a [LdButton](components/ld-button/) to your proj

When you put this component on a page, you should see a blue button with the text "Click me!" and a lightning bolt icon.

### Manually defining custom elements

When you look at the example above you may notice that we didn't have to define any custom elements anywhere. This is because the React output target includes the define custom elements logic and all custom elements get registered with the Custom Elements Registry as soon as imported (the [Stencil `includeDefineCustomElements` option](https://stenciljs.com/docs/vue#includedefinecustomelements) is set to `true`).

In some cases this convenience feature is not desireable, such as when bundling Liquid Oxygen components within your own library, or when you want to have more control over when your custom elements get registered. For this reason Liquid Oxygen exposes a React output target entry which does __not__ include the `defineCustomElements` utility.

Here is how you would implement the example above, using the React output target, that doesn not include the `defineCustomElements` helper method.

```html
<!-- SampleComponent.vue -->
<script setup lang="ts">
import { LdButton, LdIcon } from '@emdgroup-liquid/liquid/dist/vue-define-excluded'
</script>

<template>
<ld-button>
Click me!
<ld-icon name="energy" />
</ld-button>
</template>
```

Now you can register the components manually in two ways.

1. You can use the `defineCustomElements` utility.

```tsx
import { defineCustomElements } from '@emdgroup-liquid/liquid/dist/loader'
defineCustomElements()
```

2. You can register each element individually.

```tsx
import { LdButton as LdButtonCE } from '@emdgroup-liquid/liquid/dist/components/ld-button'
import { LdIcon as LdIconCE } from "@emdgroup-liquid/liquid/dist/components/ld-icon"

customElements.get('ld-button') || customElements.define('ld-button', LdButtonCE)
customElements.get('ld-icon') || customElements.define('ld-icon', LdIconCE)
```

### Events

Liquid Oxygen components aim to work similarly to native HTML elements as much as possible. In most cases, you can expect the same events and behavior from a Liquid Oxygen component and its native equivalent. Custom events are documented on the respective component pages.
Expand Down

1 comment on commit 6077647

@vercel
Copy link

@vercel vercel bot commented on 6077647 May 17, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

liquid – ./

liquid-git-main-uxsd.vercel.app
liquid-oxygen.vercel.app
liquid-uxsd.vercel.app

Please sign in to comment.