core Documentation

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be...

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy core on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name core --restart always home-assistant/core:latest

File: README.md

Stencil

[Quick Start](https://stenciljs.com/docs/getting-started#starting-a-new-project) ยท [Documentation](https://stenciljs.com/docs/introduction) ยท [Contribute](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md) ยท [Blog](https://ionicframework.com/blog/tag/stencil/)

Community:
Discord
ยท
Forums
ยท
Twitter

Getting Started

Start a new project by following our quick Getting Started guide.
We would love to hear from you!
If you have any feedback or run into issues using Stencil, please file an issue on this repository.

Examples

A Stencil component looks a lot like a class-based React component, with the addition of TypeScript decorators:

tsx
import { Component, Prop, h } from '@stencil/core';

@Component({
  tag: 'my-component',            // the name of the component's custom HTML tag
  styleUrl: 'my-component.css',   // css styles to apply to the component
  shadow: true,                   // this component uses the ShadowDOM
})
export class MyComponent {
  // The component accepts two arguments:
  @Prop() first: string;
  @Prop() last: string;

   //The following HTML is rendered when our component is used
  render() {
    return (
      
        Hello, my name is {this.first} {this.last}
      
    );
  }
}

The component above can be used like any other HTML element:

html
<my-component first="Stencil" last="JS"></my-component>

Since Stencil generates web components, they work in any major framework or with no framework at all.
In many cases, Stencil can be used as a drop in replacement for traditional frontend framework, though using it as such is certainly not required.

Contributing

Thanks for your interest in contributing!
Please take a moment to read up on our guidelines for contributing. We've created comprehensive technical documentation for contributors that explains Stencil's internal architecture, including the compiler, runtime, build system, and other core components in the /docs directory.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.


File: Readme.md

Stencil

[Quick Start](https://stenciljs.com/docs/getting-started#starting-a-new-project) ยท [Documentation](https://stenciljs.com/docs/introduction) ยท [Contribute](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md) ยท [Blog](https://ionicframework.com/blog/tag/stencil/)

Community:
Discord
ยท
Forums
ยท
Twitter

Getting Started

Start a new project by following our quick Getting Started guide.
We would love to hear from you!
If you have any feedback or run into issues using Stencil, please file an issue on this repository.

Examples

A Stencil component looks a lot like a class-based React component, with the addition of TypeScript decorators:

tsx
import { Component, Prop, h } from '@stencil/core';

@Component({
  tag: 'my-component',            // the name of the component's custom HTML tag
  styleUrl: 'my-component.css',   // css styles to apply to the component
  shadow: true,                   // this component uses the ShadowDOM
})
export class MyComponent {
  // The component accepts two arguments:
  @Prop() first: string;
  @Prop() last: string;

   //The following HTML is rendered when our component is used
  render() {
    return (
      
        Hello, my name is {this.first} {this.last}
      
    );
  }
}

The component above can be used like any other HTML element:

html
<my-component first="Stencil" last="JS"></my-component>

Since Stencil generates web components, they work in any major framework or with no framework at all.
In many cases, Stencil can be used as a drop in replacement for traditional frontend framework, though using it as such is certainly not required.

Contributing

Thanks for your interest in contributing!
Please take a moment to read up on our guidelines for contributing. We've created comprehensive technical documentation for contributors that explains Stencil's internal architecture, including the compiler, runtime, build system, and other core components in the /docs directory.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.


File: readme.md

Stencil

[Quick Start](https://stenciljs.com/docs/getting-started#starting-a-new-project) ยท [Documentation](https://stenciljs.com/docs/introduction) ยท [Contribute](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md) ยท [Blog](https://ionicframework.com/blog/tag/stencil/)

Community:
Discord
ยท
Forums
ยท
Twitter

Getting Started

Start a new project by following our quick Getting Started guide.
We would love to hear from you!
If you have any feedback or run into issues using Stencil, please file an issue on this repository.

Examples

A Stencil component looks a lot like a class-based React component, with the addition of TypeScript decorators:

tsx
import { Component, Prop, h } from '@stencil/core';

@Component({
  tag: 'my-component',            // the name of the component's custom HTML tag
  styleUrl: 'my-component.css',   // css styles to apply to the component
  shadow: true,                   // this component uses the ShadowDOM
})
export class MyComponent {
  // The component accepts two arguments:
  @Prop() first: string;
  @Prop() last: string;

   //The following HTML is rendered when our component is used
  render() {
    return (
      
        Hello, my name is {this.first} {this.last}
      
    );
  }
}

The component above can be used like any other HTML element:

html
<my-component first="Stencil" last="JS"></my-component>

Since Stencil generates web components, they work in any major framework or with no framework at all.
In many cases, Stencil can be used as a drop in replacement for traditional frontend framework, though using it as such is certainly not required.

Contributing

Thanks for your interest in contributing!
Please take a moment to read up on our guidelines for contributing. We've created comprehensive technical documentation for contributors that explains Stencil's internal architecture, including the compiler, runtime, build system, and other core components in the /docs directory.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.


File: src/declarations/readme.md

Declarations

`index.ts`

Index of every declaration within Stencil's source for convenience. Exports both public and private declarations. Meant to only be used by Stencil's source code so * as d from './declarations is easy to use.

`stencil-private`

Declarations like CompilerCtx and BuildCtx would be in here. Declarations in this file should always be safe to refactor and are never meant to be used by external code.

`stencil-public-compiler`

Build time declarations for the compiler that can be publicly exposed, but this file itself is never directly imported by user code. Declarations like Config and OutputTarget would be in here.

`stencil-public-runtime`

Client-side declarations for the runtime that can be publicly exposed, but this file itself is never directly imported by user code. Declarations like HTMLStencilElement, JSXBase, and Component would be in here.

This is also the file that would be copied to distribution dist/types directories. For example, a dist dist/types/components.d.ts file would start with import { HTMLStencilElement, JSXBase } from './stencil.public';, so the stencil.public.runtime.d.ts file should be a sibling. A distribution copy of Stencil Core declarations should not have a dependency of @stencil/core.

`stencil-core`

The actual public declarations when @stencil/core is imported by developer code. This should be a minimal list that exports with specific declarations from stencil.public.compiler and stencil.public.runtime.

`stencil-ext-modules`

The TypeScript declaration file used so that TypeScript can import .svg or .css files without throwing errors. Build steps will manually copy this to the correct location.


File: src/compiler/output-targets/readme.md

Output Targets

Stencil is able to generate components into various formats so they can be best integrated into the many different apps types, no matter what framework or bundler is used.

Output Target Terms

script: A prebuilt, stand-alone webapp already built from the components. These are already built to be loaded by just a script tag, no additional builds or bundling required. Both the www and dist output target types save an "app" into their directories. When saving the webapp into the dist/ directory, it can be easily packaged up and used with a service like unpkg.com. See https://www.npmjs.com/package/@ionic/core

collection: Source files transpiled down to simple JavaScript, and all component metadata placed on the component class as static getters. When one Stencil distribution imports another, it will use these files when generating its own distribution. What's important is that the source code of a collection is future proof, meaning no matter what version of Stencil it can import and understand the component metadata.

host: The actual "host" element sitting in the webpage's DOM.

lazy-loaded: A lazy-loaded webapp creates all the proxied host custom elements up front, but only downloads the component implementation on-demand. Lazy-loaded components work by having a proxied "host" custom element, and lazy-loads the component class and css, and rather than the host element having the "instance", such as a traditional custom element, the instance is of the lazy-loaded component class. If a Stencil library has a low number of components, then having them all packaged into a single-file would be best. But for a very large library of components, such as Ionic, it'd be best to have them lazy-loaded instead. Part of the configuration can decide when to make a library either lazy-loaded or single-file.

module: Component code meant to be imported by other bundlers in order for them to be integrated within other apps.

native: Lazy-loaded components split the host custom element and the component implementation apart. A "native" component is a traditional custom element in that the instance and host element are the same.

custom-element: Individual custom elements packaged up into stand-alone, self-contained code. Each component imports shared runtime from @stencil/core. Opposite of lazy-loaded components that define themselves and load on demand, the custom elements builds must be imported and defined by the consumer, and any lazy-loaded depends on the consumer's bundling methods.

Output Target Types

`www`

  • Default output target when not configured.
  • Generates a stand-alone app into the www/ directory.
  • Depending on the number of components and configuration, the app may be lazy-loaded of single-file.

`dist`

  • Generates modules to be imported by other bundlers, such as dist/esm/ and dist/esm-es5/ (when enabling buildEs5 config).
  • Generates an app at the root of the dist/ directory. It's the same stand-alone webapp as the www type, but located in dist so it's easy to package up and shared.
  • Generates a collection into the dist/collection/ directory to be used by other projects.

`angular`

  • Generates a wrapper Angular component proxy.
  • Web components themselves work fine within Angular, but you loose out on many of Angular's features, such as types or @ViewChild. In order for a Stencil project to fit right into the Angular ecosystem, this output target generates thin wrapper that can be imported by Angular.

`dist-hydrate-script`

  • Used by NodeJS to do Static Site Generation (SSG) and/or Server Side Rendering (SSR).
  • Used by Stencil prerendering commands.
  • Formats the components so that the server can generate new global window environments that are scoped to each rendering, rather than having global information bleed between each URL rendered.

Output Folder Structure Defaults

text
- dist/

  - cjs/ (bundler ready, cjs modules)
    - index.cjs.js
    - loader.cjs.js

  - collection/ (metadata when this is lazy-loaded dependency)
    - my-cmp/
      - my-cmp.js (esm)
      - my-cmp.css
    - collection-manifest.json
    - global.js
  
  - custom-elements (bundler ready custom elements, esm only)
    - index.js (esm)
    - index.d.ts

  - esm (bundler ready, esm modules, es2017 source)
    - index.js
    - loader.js

  - esm-es5 (buildEs5, bundler ready, esm modules, es5 source)
    - index.js
    - loader.js

  - loader (bundler entry for lazy builds)
    - cdn.js
    - index.js
    - index.cjs.js
    - index.d.ts
    - index.es2017.js
    - package.json (to import loader package, such as myapp/loader)

  - myapp (browser ready script, named from stencil config namespace)
    - myapp.css
    - myapp.esm.js
    - myapp.js (buildEs5 entry, systemjs modules, es5 source)
    - myapp.system.js (buildEs5, systemjs modules, es5 source)

  - types (dts files for each component)
    - my-cmp/
      -my-cmp.d.ts

  - index.cjs.js (dist cjs entry)
  - index.js (dist esm entry)

- hydrate
  - index.js (NodeJS ready hydrate script, cjs module)
  - index.d.ts (types for hydrate API)
  - package.json (to import hydrate package, such as myapp/hydrate)

- www/ (www output target)
  - build/
    - myapp.esm.js (browser ready esm modern script)
    - myapp.js (buildEs5, browser ready systemjs modules, es5 script)

  - index.html (optimized html from src/index.html)

- package.json (top-level package.json is not auto-updated)
- stencil.config.ts

File: src/compiler/style/css-parser/readme.md

Forked from https://github.com/reworkcss/css
Ported to ESM and Typed
Modified so to remove selectors that are not used in HTML

(The MIT License)

Copyright (c) 2012 TJ Holowaychuk [email protected]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


File: src/internal/readme.md

@stencil/core/internal

NOTE!! The @stencil/core/internal package is not meant to be consumed directly by anything other than Stencil internals. It is its own package so that it can be resolved by Stencil, but breaking changes can/will happen at any time. This isn't a "use at your own discretion" moment, but it's more of a "never use this because your code will break" fact.

`index.ts`

This is the main entry file for all of Stencil's internals, such as Stencil's runtime and compiler types. However, any public references to the internals are found in declarations/stencil-core.ts and internal/default.ts. This file is largely used to generate all of Stencil's internal types. But the transpiled JavaScript from this is not exposed.

`default.ts`

By default, when Stencil resolves @stencil/core/internal, it's going to assume it wants the client internals (rather than hydrate). So by default, @stencil/core/internal actually points to @stencil/core/internal/client.


File: src/runtime/readme.md

Lifecycle Order Of Operations

Component lifecycle events fire componentWillLoad from top to bottom, then fire componentDidLoad from bottom to top. It should take into account each component can finish lazy-loaded requests in any random order. Additionally, any componentWillLoad can return a promise that all child components should wait on until it's resolved, while still keeping the correct firing order.

text
<cmp-a>
  <cmp-b>
    <cmp-c></cmp-c>
  </cmp-b>
</cmp-a>

cmp-a - componentWillLoad
cmp-b - componentWillLoad
cmp-c - componentWillLoad
cmp-c - componentDidLoad
cmp-b - componentDidLoad
cmp-a - componentDidLoad

Hydrated CSS Visibility

By default, components are assigned visibility: hidden using their tag name as the css selector. Therefore, before the components and their descendants have finished hydrating, each component is hidden by default. This is done to prevent janky flickering as components hydrate asynchronously. As each component fully loads the hydrated css class is then added.

The hydrated css class that's added to the component assigns visibility: inherit style to the element. If any parent component is still hydrating then this component will not show until the top most component has added the hydrated css class.

Lifecycle Process

  • Connect: Synchronously within connectedCallback, each component looks for an ancestor component and adds itself as a child component if an ancestor is found.

    • Climb up the parent elements with a while loop.

    • Stop at the first element that has an s-init function.

    • If the ancestor component we found hasn't ran its lifecycle update yet, then add this component to the ancestor's s-al set. The s-al is a set of child components that are actively loading.

    • If no ancestor component is found then continue without the component setting an ancestor component.

  • Initialize Component: Initialize the component for the first time within initializeComponent.

    • If the component has already initialized loading then do nothing. Data to know if the component has started to initialize is in the host ref data, which ensures it doesn't try to initialize more than once.

    • Async request the lazy-loaded component constructor and await the response.

    • After the component implementation constructor request has been received, create a new instance of the component with the lazy-loaded constructor.

    • The constructor will directly wire the host element and lazy-loaded component instance together with the host ref data.

    • If the component has an ancestor component, but the ancestor hasn't ran its lifecycle update yet, then this component should not be initialized at this moment and shouldn't fire its componentWillLoad yet. Instead, this component should be added to the ancestor component's array of render callbacks s-rc, which would call initializeComponent again after its ready. Once the ancestor component has ran its lifecycle update, it'll then call all of its child render callbacks so that the componentWillLoad lifecycle events are in the correct order.

    • If there is no ancestor component, or the ancestor component has already rendered, then fire off the first update.

    • When ready, updateComponent will be added as an async write task and ran asynchronously.

  • First Update: The first component update and render from within updateComponent.

    • Set the lifecycle ready value s-lr to false signifying that the lifecycle update is not ready for this component.

    • Fire off componentWillLoad lifecycle.

    • Fire off componentWillRender lifecycle.

    • Add scoped css data and classes for scoped encapsulation or shadow dom encapsulation without shadow dom browser support.

    • Attach shadow root for shadow dom components.

    • Attach styles to shadow root or document depending on encapsulation.

    • First render.

    • Set the lifecycle ready value s-lr to true signifying that the lifecycle update has happened and the component is now ready for child component lifecycles.

    • Fire off all of this component's child render callbacks within s-rc. Each of the child render callbacks will fire off their own initialize component process.

    • All component descendants should fire componentWillLoad lifecycle in the correct order, top to bottom.

    • Fire postUpdateComponent. The bottom most component will not have any child render callbacks, so at this point the componentDidLoad lifecycle events should start firing from bottom to top.

    • Fire off componentDidLoad lifecycle.

    • Fire off componentDidRender lifecycle.

    • Add hydrated css class signifying the component has finished loading. At this point this component has finished updating.

    • If the component has an ancestor component, then remove this component from its set of actively loading children in s-al.

    • After removing this component from the ancestor component's s-al set, if the set is now empty then fire the ancestor component's s-init.

    • Firing s-init on the ancestor component allows the ancestor to complete its first update and fire its own componentDidLoad lifecycle event, allowing for componentDidLoad lifecycles to fire bottom to top.

    • Fire all componentOnReady resolves.

  • Subsequent Updates: All subsequent component updates and re-renders from within updateComponent.

    • Somehow setValue is triggered, either through a Prop or State update, or calling forceUpdate() on a component. If there is a change or a forced update, then setValue will add updateComponent to an async write task.

    • Fire updateComponent from async task queue.

    • Fire off componentWillUpdate lifecycle.

    • Fire off componentWillRender lifecycle.

    • Patch render.

    • Fire postUpdateComponent.

    • Fire off componentDidUpdate lifecycle.

    • Fire off componentDidRender lifecycle.

Property Descriptions

s-al: A component's Set of child components that are actively loading.

s-init: A function to be called by child components to finish initializing the component.

s-lr: The component's lifecycle ready status. true if the component has finished its lifecycle update, falsy if it is actively updating and has not fired off either componentWillLoad or componentWillUpdate.

s-rc: A component's array of child component render callbacks. After a component renders, it should then fire off all of its child component render callbacks.


File: src/testing/jest/README.md

Jest Support in Stencil

This directory contains support for the Jest testing library.

Installing Dependencies

To be able to work on the sub-projects in this directory, Jest dependencies are required to be installed explicitly.
To do so, one may either:

  1. (Recommended) Run npm run install.jest from the root of the repository to install all Jest dependencies
  2. Run the install-dependencies.sh script found in this directory to install all Jest dependencies
  3. Run npm ci in the Jest version-specific directory you plan on working in

Adding Support for a New Version of Jest

The steps for adding support for a new version of Jest can be found below.
These steps are intended to be followed in order, and be a part of a single pull request.
It is HIGHLY recommended that you create a commit for each step in the process.
This allows for 'well known' commits that map directly back to these steps to be created, speeding up the review process.

  1. In this directory, there are several version-specific directories to support Jest.
    For example, jest-27-and-under/ is for Jest v27 and below, jest-28/ is for Jest v28, etc.
    To start, create a copy of the entire directory contents for the latest version of Jest in this directory, ensuring the version number is in the directory name.

    If we wanted to add support for Jest v29 and had the following existing directory structure:

    text
    โ””โ”€โ”€ src/testing/jest/
        โ”œโ”€โ”€ jest-27-and-under
        โ””โ”€โ”€ jest-28

    Adding support for Jest v29 would begin with making a copy of jest-28/ (the latest supported version) and naming it jest-29/.
    The end result of this step are two identical copies of the copied directory, with one bearing the name of the new version of Jest:

    text
    โ””โ”€โ”€ src/testing/jest/
        โ”œโ”€โ”€ jest-27-and-under
        โ”œโ”€โ”€ jest-28
        โ””โ”€โ”€ jest-29            <- Newly copied version of jest-28, just with a different name
  2. Commit your changes to help your reviewers out - this makes it easier to review changes that are coming down the line.
    Last reminder, please do this after every step.

  3. Delete the package-lock.json file that was copied into your new directory.
    We'll regenerate this later after a few modifications have been made to package.json in the next step.

  4. Update the name and description of the package in the newly created directory's pacakge.json to reflect the version of Jest it supports.

    diff
    diff --git a/src/testing/jest/jest-29/package.json b/src/testing/jest/jest-29/package.json
    index 92b5ee419..bd1614fe0 100644
    --- a/src/testing/jest/jest-29/package.json
    +++ b/src/testing/jest/jest-29/package.json
    @@ -1,5 +1,5 @@
    {
    -  "name": "@stencil/jest-28",
    +  "name": "@stencil/jest-29",
       "version": "1.0.0",
    -  "description": "Internal package for supporting Jest 28 with Stencil",
    +  "description": "Internal package for supporting Jest 29 with Stencil",
       "license": "MIT",
  5. Update any Jest related dependencies to use the targeted version of Jest.
    It is up to you to determine/verify the packages needed here.

    bash
    $ cd src/testing/jest/jest-29
    $ npm i -D jest@29 @types/jest@29

    Note: Running npm install will regenerate the package-lock.json file you deleted in a previous step.
    Note: All dependencies can simply be dev-dependencies, since they're only used for type checking.

  6. Update renovate.json to not bump Jest beyond the version that this directory is responsible for:

    diff
    index 4861b2477..7cf75e16d 100644
    --- a/renovate.json5
    +++ b/renovate.json5
    @@ -98,6 +98,11 @@
           matchPackageNames: ['@types/jest', 'jest'],
           allowedVersions: '<=28'
         },
    +    {
    +      matchFileNames: ["src/testing/jest/jest-29/package.json"],
    +      matchPackageNames: ['@types/jest', 'jest'],
    +      allowedVersions: '<=29'
    +    },
         {

    Note how:

    • matchFileNames maps to the new Jest directory's package.json
    • matchPackageNames lists the packages that were upgraded earlier
    • allowedVersions allows versions less than or equal to the version we're adding support for
  7. Add the new version of Jest to the Component Starter smoke tests:

    diff
    index 16560a659..a4bee5308 100644
    --- a/.github/workflows/test-component-starter.yml
    +++ b/.github/workflows/test-component-starter.yml
    @@ -16,7 +16,7 @@ jobs:
    strategy:
    fail-fast: false
    matrix:
    -        jest: ['24', '25', '26', '27', '28']
    +        jest: ['24', '25', '26', '27', '28', '29']
             node: ['16', '18', '20']
             os: ['ubuntu-latest', 'windows-latest']
      runs-on: ${{ matrix.os }}
  8. Rename the JestFacade implementation in the new directory's jest-facade.ts file.
    The number in the class name should match the version of Jest we're adding support for.
    It is recommended that you use your editor's renaming/refactoring utility to do this step:

    diff
    import type * as d from '@stencil/core/internal';
    import { isString } from '@utils';
    
    -import { Jest28Stencil } from './jest-facade';
    +import { Jest29Stencil } from './jest-facade';
    
    /**
    * Helper function for retrieving legacy Jest options. These options have been provided as defaults to Stencil users
      @@ -147,7 +147,7 @@ export function buildJestConfig(config: d.ValidatedConfig): string {
      jestConfig.verbose = stencilConfigTesting.verbose;
      }
    
    -  jestConfig.testRunner = new Jest28Stencil().getDefaultJestRunner();
    +  jestConfig.testRunner = new Jest29Stencil().getDefaultJestRunner();
    
       return JSON.stringify(jestConfig);
       }
       diff --git a/src/testing/jest/jest-29/jest-facade.ts b/src/testing/jest/jest-29/jest-facade.ts
       index 3c7aa949c..3dea9b42b 100644
       --- a/src/testing/jest/jest-29/jest-facade.ts
       +++ b/src/testing/jest/jest-29/jest-facade.ts
       @@ -10,7 +10,7 @@ import { jestSetupTestFramework } from './jest-setup-test-framework';
       /**
        * `JestFacade` implementation for communicating between this directory's version of Jest and Stencil
        */
    -  export class Jest28Stencil implements JestFacade {
    +  export class Jest29Stencil implements JestFacade {
        getJestCliRunner() {
        return runJest;
      }
  9. Update the jest-stencil-connector.ts to call the new JestFacade implementation:

    diff
    index 50372d9df..81f9e6cf9 100644
    --- a/src/testing/jest/jest-stencil-connector.ts
    +++ b/src/testing/jest/jest-stencil-connector.ts
    @@ -10,6 +10,7 @@
     import semverMajor from 'semver/functions/major';
     
     import { Jest28Stencil } from './jest-28/jest-facade';
    +import { Jest29Stencil } from './jest-29/jest-facade';
     import { getJestMajorVersion } from './jest-apis';
     import { JestFacade } from './jest-facade';
     
    @@ -40,9 +41,10 @@ const getJestFacade = (): JestFacade => {
         const version = getVersion();
         else if (version <= 28) {
           JEST_STENCIL_FACADE = new Jest28Stencil();
    +    } else if (version === 29) {
    +      JEST_STENCIL_FACADE = new Jest29Stencil();
         } else {
  10. Set the recommended and max version to the new version of Jest:

    diff
    index c5bf2ed14..9936ce738 100644
    --- a/src/sys/node/node-sys.ts
    +++ b/src/sys/node/node-sys.ts
    @@ -664,9 +664,9 @@ export function createNodeSys(c: { process?: any; logger?: Logger } = {}): Compi
       const nodeResolve = new NodeResolveModule();
     
       sys.lazyRequire = new NodeLazyRequire(nodeResolve, {
    -    '@types/jest': { minVersion: '24.9.1', recommendedVersion: '28', maxVersion: '28.0.0' },
    -    jest: { minVersion: '24.9.0', recommendedVersion: '28', maxVersion: '28.0.0' },
    -    'jest-cli': { minVersion: '24.9.0', recommendedVersion: '28', maxVersion: '28.0.0' },
    +    '@types/jest': { minVersion: '24.9.1', recommendedVersion: '29', maxVersion: '29.0.0' },
    +    jest: { minVersion: '24.9.0', recommendedVersion: '29', maxVersion: '29.0.0' },
    +    'jest-cli': { minVersion: '24.9.0', recommendedVersion: '29', maxVersion: '29.0.0' },
         puppeteer: { minVersion: '10.0.0', recommendedVersion: '20' },
         'puppeteer-core': { minVersion: '10.0.0', recommendedVersion: '20' },
         'workbox-build': { minVersion: '4.3.1', recommendedVersion: '4.3.1' },
  11. It's time to get the project to compile.
    Build Stencil and resolve any typing errors that have arisen from adding new versions of Jest.

  12. Once Stencil compiles, generate a version that can be installed in a Stencil component starter project (either a tarball or a dev build) and install it into the component starter.
    Attempt to run the tests, working through any initial errors that you may run into.
    Consider working through the Jest Breaking Changes guide for the current version that you are adding support for.

  13. Perform a final pass through the Jest Breaking Changes guide for the current version that you are adding support for.
    Ensure any changes that ought to be made are completed.
    Note: Just because something didn't give us a runtime error, doesn't mean it should not be changed.

  14. Attempt to use your version of Stencil in the Ionic Framework.
    Their unit tests should continue to run and pass as a result of this effort.

  15. Once your PR is merged, please ensure that the CI gate checks are updated to enforce successful runs of the new version of Jest for the Stencil Component Starter smoke test.


File: docs/README.md

Stencil Technical Documentation

Welcome to the Stencil technical documentation. This documentation is designed for contributors who want to understand the internal architecture and implementation details of Stencil. It provides comprehensive information about how Stencil works under the hood.

Overview

Stencil is a compiler that generates Web Components and builds high-performance web applications. It combines the best concepts of the most popular frameworks into a simple build-time tool.

Architecture Overview

mermaid
graph TB
    subgraph "Build Time"
        CLI[CLI Entry Point] --> Compiler[Compiler Core]
        Compiler --> TS[TypeScript Compiler]
        Compiler --> Bundler[Rollup Bundler]
        Compiler --> Optimizer[Build Optimizer]
    end
    
    subgraph "Development"
        DevServer[Dev Server] --> HMR[Hot Module Replacement]
        DevServer --> WS[WebSocket Server]
    end
    
    subgraph "Runtime"
        ComponentRuntime[Component Runtime] --> VDOM[Virtual DOM]
        ComponentRuntime --> LC[Lifecycle Manager]
        ComponentRuntime --> PS[Proxy State]
    end
    
    subgraph "Server Side"
        Hydrate[Hydrate App] --> MockDoc[Mock Document]
        Hydrate --> SSR[SSR Renderer]
    end
    
    CLI -.-> DevServer
    Compiler --> ComponentRuntime
    Compiler --> Hydrate

Core Components

[CLI](./cli.md)

Location: /src/cli

The command-line interface that serves as the entry point for all Stencil operations. It handles:

  • Command parsing and validation
  • Configuration loading
  • Task orchestration (build, serve, test, etc.)
  • Version checking and telemetry
  • Process management

[Compiler](./compiler.md)

Location: /src/compiler

The heart of Stencil that transforms TypeScript/JSX components into optimized web components. Key responsibilities:

  • TypeScript transformation and compilation
  • Component metadata extraction
  • Build optimization and bundling
  • Output target generation
  • Style processing
  • Static analysis
  • Build orchestration and caching
  • Incremental compilation

[Runtime](./runtime.md)

Location: /src/client, /src/runtime, /src/internal

The client-side code that powers Stencil components in the browser:

  • Component lifecycle management
  • Virtual DOM implementation
  • State management and reactivity
  • Event handling
  • Lazy loading
  • Hydration support

[Dev Server](./dev-server.md)

Location: /src/dev-server

Development server with hot module replacement:

  • HTTP server for serving builds
  • WebSocket server for HMR
  • File watching and rebuilding
  • Browser auto-refresh
  • Error overlay
  • Request proxying

[Hydrate](./hydrate.md)

Location: /src/hydrate

Server-side rendering and hydration support:

  • Node.js rendering environment
  • Component pre-rendering
  • Static site generation
  • Hydration markers
  • SEO optimization

[Mock Doc](./mock-doc.md)

Location: /src/mock-doc

Lightweight DOM implementation for server-side rendering:

  • DOM API implementation
  • Window and document globals
  • CSS parsing
  • HTML parsing and serialization
  • Performance optimizations

[Declarations](./declarations.md)

Location: /src/declarations

TypeScript type definitions and interfaces that define:

  • Public API contracts
  • Internal data structures
  • Configuration schemas
  • Build metadata formats

Deprecated Components

[Testing](./testing-deprecated.md)

Location: /src/testing

The built-in test runner based on Jest (deprecated). Users should migrate to:

[Screenshot Testing](./screenshot-deprecated.md)

Location: /src/screenshot

Visual regression testing (deprecated). Will be removed in the next major version.

Key Concepts

Build Process

  1. Configuration Loading: Parse and validate stencil.config.ts
  2. Discovery: Find all components in the source
  3. Analysis: Extract metadata from decorators
  4. Transformation: Convert TypeScript/JSX to JavaScript
  5. Bundling: Create optimized bundles
  6. Output Generation: Generate files for each output target

Component Lifecycle

Components follow a predictable lifecycle during initialization and updates:

  1. Constructor: Element created
  2. connectedCallback: Element added to DOM
  3. componentWillLoad: Before first render
  4. componentWillRender: Before each render
  5. render: Generate virtual DOM
  6. componentDidRender: After each render
  7. componentDidLoad: After first render
  8. componentDidUpdate: After updates
  9. disconnectedCallback: Element removed from DOM

Multi-Threading Architecture

Stencil uses a multi-threaded architecture for better performance:

mermaid
graph LR
    Main[Main Thread] --> W1[Worker 1]
    Main --> W2[Worker 2]
    Main --> W3[Worker N]
    
    W1 --> Tasks1[TypeScriptCompilation]
    W2 --> Tasks2[BundleGeneration]
    W3 --> Tasks3[StyleProcessing]

Building Stencil

[Scripts Build System](./scripts.md)

Location: /scripts

The build system used to develop and build Stencil itself:

  • Uses esbuild for bundling
  • Bundles TypeScript, Terser, and Parse5
  • Creates all distributable packages
  • Handles release automation
  • Validates build outputs

This is separate from Stencil's compiler - it's specifically for building the Stencil project during development.

Building and Development

To work on Stencil itself:

bash
# Clone the repository
git clone https://github.com/ionic-team/stencil.git
cd stencil

# Install dependencies
npm install

# Build Stencil
npm run build

# Run tests
npm test

# Start development
npm run dev

For detailed compiler documentation and build process information, see the Compiler documentation.