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:
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:
<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:
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:
<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:
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:
<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
appinto thewww/directory. - Depending on the number of components and configuration, the app may be lazy-loaded of single-file.
`dist`
- Generates
modulesto be imported by other bundlers, such asdist/esm/anddist/esm-es5/(when enabling buildEs5 config). - Generates an
appat the root of thedist/directory. It's the same stand-alone webapp as thewwwtype, but located in dist so it's easy to package up and shared. - Generates a
collectioninto thedist/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
- 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.tsFile: 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.
<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 - componentDidLoadHydrated 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-initfunction.If the ancestor component we found hasn't ran its lifecycle update yet, then add this component to the ancestor's
s-alset. Thes-alis 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
componentWillLoadyet. Instead, this component should be added to the ancestor component's array of render callbackss-rc, which would callinitializeComponentagain after its ready. Once the ancestor component has ran its lifecycle update, it'll then call all of its child render callbacks so that thecomponentWillLoadlifecycle 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,
updateComponentwill 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-lrtofalsesignifying that the lifecycle update is not ready for this component.Fire off
componentWillLoadlifecycle.Fire off
componentWillRenderlifecycle.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-lrtotruesignifying 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
componentWillLoadlifecycle in the correct order, top to bottom.Fire
postUpdateComponent. The bottom most component will not have any child render callbacks, so at this point thecomponentDidLoadlifecycle events should start firing from bottom to top.Fire off
componentDidLoadlifecycle.Fire off
componentDidRenderlifecycle.Add
hydratedcss 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-alset, if the set is now empty then fire the ancestor component'ss-init.Firing
s-initon the ancestor component allows the ancestor to complete its first update and fire its owncomponentDidLoadlifecycle event, allowing forcomponentDidLoadlifecycles to fire bottom to top.Fire all
componentOnReadyresolves.
Subsequent Updates: All subsequent component updates and re-renders from within
updateComponent.Somehow
setValueis triggered, either through aProporStateupdate, or callingforceUpdate()on a component. If there is a change or a forced update, thensetValuewill addupdateComponentto an async write task.Fire
updateComponentfrom async task queue.Fire off
componentWillUpdatelifecycle.Fire off
componentWillRenderlifecycle.Patch render.
Fire
postUpdateComponent.Fire off
componentDidUpdatelifecycle.Fire off
componentDidRenderlifecycle.
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:
- (Recommended) Run
npm run install.jestfrom the root of the repository to install all Jest dependencies - Run the
install-dependencies.shscript found in this directory to install all Jest dependencies - Run
npm ciin 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.
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-28Adding support for Jest v29 would begin with making a copy of
jest-28/(the latest supported version) and naming itjest-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 nameCommit 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.Delete the
package-lock.jsonfile that was copied into your new directory.
We'll regenerate this later after a few modifications have been made topackage.jsonin the next step.Update the name and description of the package in the newly created directory's
pacakge.jsonto reflect the version of Jest it supports.diffdiff --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",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@29Note: Running
npm installwill regenerate thepackage-lock.jsonfile you deleted in a previous step.
Note: All dependencies can simply be dev-dependencies, since they're only used for type checking.Update
renovate.jsonto not bump Jest beyond the version that this directory is responsible for:diffindex 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:
matchFileNamesmaps to the new Jest directory'spackage.jsonmatchPackageNameslists the packages that were upgraded earlierallowedVersionsallows versions less than or equal to the version we're adding support for
Add the new version of Jest to the Component Starter smoke tests:
diffindex 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 }}Rename the
JestFacadeimplementation in the new directory'sjest-facade.tsfile.
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:diffimport 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; }Update the
jest-stencil-connector.tsto call the newJestFacadeimplementation:diffindex 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 {Set the recommended and max version to the new version of Jest:
diffindex 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' },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.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.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.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.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
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 --> HydrateCore 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
- Configuration Loading: Parse and validate stencil.config.ts
- Discovery: Find all components in the source
- Analysis: Extract metadata from decorators
- Transformation: Convert TypeScript/JSX to JavaScript
- Bundling: Create optimized bundles
- Output Generation: Generate files for each output target
Component Lifecycle
Components follow a predictable lifecycle during initialization and updates:
- Constructor: Element created
- connectedCallback: Element added to DOM
- componentWillLoad: Before first render
- componentWillRender: Before each render
- render: Generate virtual DOM
- componentDidRender: After each render
- componentDidLoad: After first render
- componentDidUpdate: After updates
- disconnectedCallback: Element removed from DOM
Multi-Threading Architecture
Stencil uses a multi-threaded architecture for better performance:
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:
# 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 devFor detailed compiler documentation and build process information, see the Compiler documentation.