### Clone and Build Stencil Source: https://github.com/stenciljs/core/blob/main/docs/README.md Commands to clone the Stencil repository, install dependencies, build the project, run tests, and start the development server. ```bash git clone https://github.com/ionic-team/stencil.git cd stencil npm install npm run build npm test npm run dev ``` -------------------------------- ### Stencil Generate Command Example Source: https://github.com/stenciljs/core/blob/main/docs/cli.md Example of using the 'stencil generate' command to scaffold a new component. ```bash stencil generate my-component ``` -------------------------------- ### Stencil Configuration Example Source: https://github.com/stenciljs/core/blob/main/docs/declarations.md Example of how to define the main configuration for a Stencil project using the Config interface. ```typescript import type { Config } from '@stencil/core'; export const config: Config = { // Configuration options }; ``` -------------------------------- ### Cross-Platform Testing Setup Source: https://github.com/stenciljs/core/blob/main/docs/screenshot-deprecated.md Defines platforms for cross-platform testing and mocks different platforms for E2E page setup. ```typescript const platforms = [ { os: 'darwin', browser: 'chrome' }, { os: 'win32', browser: 'edge' }, { os: 'linux', browser: 'firefox' } ]; // Mock different platforms beforeEach(async () => { const platform = platforms[0]; page = await newE2EPage({ userAgent: getUserAgent(platform), viewport: { width: 1200, height: 800, deviceScaleFactor: platform.os === 'darwin' ? 2 : 1 } }); }); ``` -------------------------------- ### Example tsconfig.json with path aliases Source: https://github.com/stenciljs/core/blob/main/BREAKING_CHANGES.md Illustrates how to configure path aliases in tsconfig.json for module resolution. ```json { "compilerOptions": { "baseUrl": ".", "paths": { "@utils": ["src/utils/index.ts"] } } } ``` -------------------------------- ### Component File Structure Example Source: https://github.com/stenciljs/core/blob/main/STYLE_GUIDE.md Illustrates the recommended directory structure for Stencil components, with each component having its own directory containing implementation and style files. ```bash ├── card │ ├── card.ios.scss │ ├── card.md.scss │ ├── card.scss │ ├── card.tsx │ └── test │ └── basic │ ├── e2e.js │ └── index.html ├── card-content │ ├── card-content.ios.scss │ ├── card-content.md.scss │ ├── card-content.scss │ └── card-content.tsx ├── card-title │ ├── card-title.ios.scss │ ├── card-title.md.scss │ ├── card-title.scss ``` -------------------------------- ### Stencil Jest Environment Setup Source: https://github.com/stenciljs/core/blob/main/docs/testing-deprecated.md Extend Jest's Node environment to include Stencil-specific globals and setup, such as mocking platform APIs and setting up `window` and `document`. ```typescript // jest/jest-environment.ts export class StencilEnvironment extends NodeEnvironment { constructor(config: Config) { super(config); // Set up globals this.global.fetch = mockFetch; this.global.CSS = mockCSS; this.global.CSSStyleSheet = MockCSSStyleSheet; } async setup() { await super.setup(); // Initialize platform const { win, doc } = mockPlatform(); this.global.window = win; this.global.document = doc; } } ``` -------------------------------- ### Install Jest Dependencies Source: https://github.com/stenciljs/core/blob/main/src/testing/jest/README.md Install the specific Jest version and its types as dev dependencies in the new Jest version directory. ```bash $ cd src/testing/jest/jest-29 $ npm i -D jest@29 @types/jest@29 ``` -------------------------------- ### Dev Server Testing Example Source: https://github.com/stenciljs/core/blob/main/docs/dev-server.md Illustrates how to test the development server's functionality, including serving static files and establishing WebSocket connections. Uses a random port for testing. ```typescript describe('dev-server', () => { let server: DevServer; beforeEach(async () => { server = await start({ root: './test-www', port: 0 // Random port }); }); afterEach(() => server.close()); it('should serve static files', async () => { const res = await fetch(`${server.browserUrl}/index.html`); expect(res.status).toBe(200); expect(res.headers.get('content-type')).toBe('text/html'); }); it('should establish WebSocket connection', (done) => { const ws = new WebSocket(server.browserUrl.replace('http', 'ws')); ws.on('open', done); }); }); ``` -------------------------------- ### GitHub Actions for Screenshot Tests Source: https://github.com/stenciljs/core/blob/main/docs/screenshot-deprecated.md Example GitHub Actions workflow for running screenshot tests and uploading diffs on failure. ```yaml - name: Screenshot Tests run: | npm run test.screenshot - name: Upload Screenshots if: failure() uses: actions/upload-artifact@v2 with: name: screenshot-diffs path: screenshot/diff/ ``` -------------------------------- ### Use a Stencil Component Source: https://github.com/stenciljs/core/blob/main/readme.md This example demonstrates how to use a Stencil component in HTML. It shows passing properties to the custom element. ```html ``` -------------------------------- ### Static Component Example Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md A basic component with no state or properties, resulting in a minimal runtime impact. ```typescript @Component({ tag: 'my-header' }) export class MyHeader { render() { return
Welcome!
; } } ``` -------------------------------- ### JsonDocsMethod ComplexType Example Source: https://github.com/stenciljs/core/blob/main/BREAKING_CHANGES.md Example of JSON-formatted documentation for a @Method, including complex type information. ```json { "complexType": { "signature": "(event?: UIEvent) => Promise", "parameters": [ { "tags": [ { "name": "param", "text": "event The user interface event that called the open." } ], "text": "The user interface event that called the open." } ], "references": { "Promise": { "location": "global", "id": "global::Promise" }, "UIEvent": { "location": "global", "id": "global::UIEvent" }, "HTMLElement": { "location": "global", "id": "global::HTMLElement" } }, "return": "Promise" } } ``` -------------------------------- ### Install Puppeteer v10+ and uninstall @types/puppeteer Source: https://github.com/stenciljs/core/blob/main/BREAKING_CHANGES.md Ensure Puppeteer v10 or higher is installed and remove the `@types/puppeteer` package as it is no longer necessary. ```bash $ npm install puppeteer $ npm uninstall @types/puppeteer ``` -------------------------------- ### Runtime Generation: Example BUILD Object Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md Generates a custom BUILD object based on the aggregated component features for a simple app. ```typescript export const BUILD = { isDev: false, isBrowser: true, isServer: false, isTesting: false, member: false, // No props or state! reflect: false, // No reflected attributes! updatable: false, // Components never update! // ... only what you need }; ``` -------------------------------- ### HTML Tag Prefix Recommendation Source: https://github.com/stenciljs/core/blob/main/STYLE_GUIDE.md Demonstrates the recommended prefixing strategy for web component HTML tags to prevent naming collisions, using 'ion-' as an example for Ionic components. ```html ion-button ion-header ``` -------------------------------- ### Example Commit Message Source: https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md Follow this format for commit messages to ensure clarity and consistency. It includes type, scope, subject, body, and issue references. ```text fix(runtime): prevent watchers from prematurely firing Wait for the CustomElementRegistry to mark the component as ready before setting `isWatchReady`. Otherwise, watchers may fire prematurely if `customElements.get()` or `customElements.whenDefined()` resolve _before_ Stencil has completed instantiating a component fixes: #123 STENCIL-13: Watchers Not Firing as Expected when using the Custom Elements Build BREAKING CHANGE: Watchers may appear to not fire in existing applications, when this is the expected behavior. ``` -------------------------------- ### Stencil Component Structure Example Source: https://github.com/stenciljs/core/blob/main/STYLE_GUIDE.md Illustrates the typical order and usage of decorators and methods within a Stencil component class. Follow this structure for maintainability and clarity. ```typescript @Component({ tag: 'ion-something', styleUrl: 'something.scss', styleUrls: { ios: 'something.ios.scss', md: 'something.md.scss', wp: 'something.wp.scss' }, host: { theme: 'something' } }) export class Something { /** * 1. Own Properties * Always set the type if a default value has not * been set. If a default value is being set, then type * is already inferred. List the own properties in * alphabetical order. Note that because these properties * do not have the @Prop() decorator, they will not be exposed * publicly on the host element, but only used internally. */ num: number; someText = 'default'; /** * 2. Reference to host HTML element. * Inlined decorator */ @Element() el: HTMLElement; /** * 3. State() variables * Inlined decorator, alphabetical order. */ @State() isValidated: boolean; @State() status = 0; /** * 4. Public Property API * Inlined decorator, alphabetical order. These are * different than "own properties" in that public props * are exposed as properties and attributes on the host element. * Requires JSDocs for public API documentation. */ @Prop() content: string; @Prop() enabled: boolean; @Prop() menuId: string; @Prop() type = 'overlay'; /** * NOTE: Prop lifecycle events SHOULD go just behind the Prop they listen to. * This makes sense since both statements are strongly connected. * - If renaming the instance variable name you must also update the name in @Watch() * - Code is easier to follow and maintain. */ @Prop() swipeEnabled = true; @Watch('swipeEnabled') swipeEnabledChanged() { this.updateState(); } /** * 5. Events section * Inlined decorator, alphabetical order. * Requires JSDocs for public API documentation. */ @Event() ionClose: EventEmitter; @Event() ionDrag: EventEmitter; @Event() ionOpen: EventEmitter; /** * 6. Component lifecycle events * Ordered by their natural call order, for example * WillLoad should go before DidLoad. */ connectedCallback() {} componentWillLoad() {} componentDidLoad() {} disconnectedCallback() {} /** * 7. Listeners * It is ok to place them in a different location * if makes more sense in the context. Recommend * starting a listener method with "on". * Always use two lines. */ @Listen('click', { enabled: false }) onClick(ev: UIEvent) { console.log('hi!') } /** * 8. Public methods API * These methods are exposed on the host element. * Always use two lines. * Requires JSDocs for public API documentation. */ @Method() open() { ... } @Method() close() { ... } /** * 9. Local methods * Internal business logic. These methods cannot be * called from the host element. */ prepareAnimation(): Promise { ... } updateState() { ... } /** * 10. hostData() function * Used to dynamically set host element attributes. * Should be placed directly above render() */ hostData() { return { attribute: 'navigation', side: this.isRightSide ? 'right' : 'left', type: this.type, class: { 'something-is-animating': this.isAnimating } }; } /** * 11. render() function * Always the last one in the class. */ render() { return ( ); } } ``` -------------------------------- ### Component Initialization Logic Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md The `initializeComponent` function handles the setup of a component instance. It includes optimizations for lazy loading, property proxying, and instance tracking, which are conditionally included based on build flags. ```typescript // src/runtime/initialize-component.ts:23-90 const initializeComponent = async (elm, hostRef, cmpMeta) => { if ((hostRef.$flags$ & HOST_FLAGS.hasInitializedComponent) === 0) { hostRef.$flags$ |= HOST_FLAGS.hasInitializedComponent; const bundleId = cmpMeta.$lazyBundleId$; // This entire lazy loading section is removed if BUILD.lazyLoad is false if (BUILD.lazyLoad && bundleId) { const Cstr = await loadModule(cmpMeta, hostRef); // Property proxying only added if components have props/state if (BUILD.member && !Cstr.isProxied) { proxyComponent(Cstr, cmpMeta, PROXY_FLAGS.proxyState); Cstr.isProxied = true; } // Instance creation tracking only if needed if (BUILD.member) { hostRef.$flags$ |= HOST_FLAGS.isConstructingInstance; } new Cstr(hostRef); if (BUILD.member) { hostRef.$flags$ &= ~HOST_FLAGS.isConstructingInstance; } } // Schedule first render scheduleUpdate(hostRef, true); } }; ``` -------------------------------- ### Interactive Component Example Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md A component with state management and event listeners, demonstrating a moderate runtime impact. ```typescript @Component({ tag: 'my-counter' }) export class MyCounter { @State() count = 0; @Listen('click') increment() { this.count++; } render() { return
Count: {this.count}
; } } ``` -------------------------------- ### Update Jest Configuration with Preset Source: https://github.com/stenciljs/core/blob/main/BREAKING_CHANGES.md Replaces manual Jest configuration with the `@stencil/core/testing` preset. This simplifies Jest setup when running tests directly. ```diff "jest": { + "preset": "@stencil/core/testing" - "transform": { - "^.+\.(ts|tsx)$": "/node_modules/@stencil/core/testing/jest.preprocessor.js" - }, - "testRegex": "(/__tests__/.*|\.(test|spec))\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ] } ``` -------------------------------- ### Open Browser Utility Source: https://github.com/stenciljs/core/blob/main/docs/dev-server.md Opens the default web browser to a specified URL. Detects the operating system to use the correct command ('open', 'start', or 'xdg-open'). ```typescript const openBrowser = async (url: string) => { const platform = process.platform; const commands = { darwin: 'open', win32: 'start', linux: 'xdg-open' }; const command = commands[platform]; if (command) { exec(`${command} ${url}`); } }; ``` -------------------------------- ### Structure a WebdriverIO Test Suite Source: https://github.com/stenciljs/core/blob/main/test/wdio/README.md Organize your Stencil component tests using the standard `describe`/`it` syntax. Use `beforeEach` hooks for common setup tasks like rendering the component. ```tsx import { h } from '@stencil/core'; import { render } from '@wdio/browser-runner/stencil'; import { $, expect } from '@wdio/globals'; describe('attribute-basic', function () { before(async () => { render({ template: () => , }); }); it('button click rerenders', async () => { await expect($('.single')).toHaveText('single'); // ... }); }); ``` -------------------------------- ### Runtime Dead Code Elimination Example 2 Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md Shows how BUILD.member and BUILD.lazyLoad flags control the inclusion of component initialization logic. Property and state handling code is only included if these flags are true. ```typescript if (BUILD.member && BUILD.lazyLoad) { // Property handling only included if needed initializeComponent(elm, hostRef, cmpMeta); } ``` -------------------------------- ### Stencil Component Example Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md A basic Stencil component demonstrating the @Component decorator and a simple render function. This component requires shadow DOM support and rendering capabilities. ```typescript @Component({ tag: 'my-simple-button', shadow: true }) export class MySimpleButton { render() { return ; } } ``` -------------------------------- ### Stencil Component TypeScript Example Source: https://github.com/stenciljs/core/blob/main/docs/compiler.md Illustrates a Stencil component using decorators like @Component, @Prop, @State, @Event, and @Method. This code is transformed into standard JavaScript with static properties. ```typescript @Component({ tag: 'my-button', styleUrl: 'my-button.css', shadow: true }) export class MyButton { @Prop() size: string; @State() clicked = false; @Event() myClick: EventEmitter; @Method() async doSomething() { // ... } render() { return ; } } ``` -------------------------------- ### Prerender Pages for Static Site Generation Source: https://github.com/stenciljs/core/blob/main/docs/hydrate.md This function generates static pages by starting a dev server, crawling URLs, rendering each page, and writing the output to disk. It's the core of Stencil's static site generation. ```typescript export const prerenderPages = async ( config: PrerenderConfig ): Promise => { const results: PrerenderResults = { diagnostics: [], urls: [] }; // Start dev server const devServer = await startDevServer(config); // Crawl and render pages const crawler = createCrawler(config); const urlsToRender = await crawler.discoverUrls(config.entryUrls); for (const url of urlsToRender) { const page = await renderPage(devServer, url, config); // Write to disk await writePage(page, config); results.urls.push({ url: page.url, filePath: page.filePath }); } await devServer.close(); return results; }; ``` -------------------------------- ### Discover URLs for Prerendering Source: https://github.com/stenciljs/core/blob/main/docs/hydrate.md This function finds all pages to prerender by starting from entry URLs and recursively discovering linked pages that should be prerendered according to the configuration. It uses a set to avoid revisiting URLs. ```typescript const discoverUrls = async ( entryUrls: string[], config: PrerenderConfig ): Promise> => { const discovered = new Set(entryUrls); const toVisit = [...entryUrls]; while (toVisit.length > 0) { const url = toVisit.shift(); const page = await fetchPage(url); // Extract links const links = extractLinks(page.html); for (const link of links) { if (shouldPrerender(link, config) && !discovered.has(link)) { discovered.add(link); toVisit.push(link); } } } return discovered; }; ``` -------------------------------- ### Display Build Logs Source: https://github.com/stenciljs/core/blob/main/src/dev-server/templates/initial-load.html Initializes a toast notification and sets up an event listener to display build log messages. The toast appears after a short delay. ```javascript setTimeout(function() { document.querySelector('.toast').classList.add('active'); }, 100); ``` ```javascript var logOutput = document.getElementById('log-output'); window.addEventListener('devserver:buildlog', function(ev) { var buildLog = ev.detail; if (buildLog && buildLog.messages) { logOutput.innerText = buildLog.messages.join('\n'); } }); ``` -------------------------------- ### Stencil Build Entry Point Source: https://github.com/stenciljs/core/blob/main/docs/scripts.md The build process begins here when 'npm run build' is executed. It slices process arguments and passes them to the main build runner. ```typescript const stencilProjectRoot = join(__dirname, '..'); const args = process.argv.slice(2); build.run(stencilProjectRoot, args); ``` -------------------------------- ### Conventional Commits Footer Example Source: https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md Example of a commit message footer including issue fixes and breaking changes. Ensure a newline separates the body from the footer, and between footer items if multiple are present. ```git fixes: #123 STENCIL-13: Watchers Not Firing as Expected when using the Custom Elements Build BREAKING CHANGE: Watchers may appear to not fire in existing applications, when this is the expected behavior. ``` -------------------------------- ### Stencil CLI Build Entry Point Source: https://github.com/stenciljs/core/blob/main/docs/compiler.md This code initiates the Stencil build process by loading and validating the configuration file. It then proceeds to the main build task. ```typescript export const run = async (init: CliInitOptions) => { const { args, logger, sys } = init; const flags = parseFlags(args); // Load and validate your stencil.config.ts const validated = await coreCompiler.loadConfig({ config: { flags }, configPath: foundConfig.configPath, logger, sys, }); // Now we can start the build! await taskBuild(coreCompiler, validated.config); }; ``` -------------------------------- ### Get Host Element Reference with @Element() Source: https://context7.com/stenciljs/core/llms.txt Use @Element() to get a typed reference to the component's host DOM element. This is useful for interacting with the Shadow DOM, accessing child elements, or calling imperative DOM methods. The property should be typed as HTMLElement. ```tsx import { Component, Element, Method, h } from '@stencil/core'; @Component({ tag: 'focus-trap', shadow: true }) export class FocusTrap { @Element() el!: HTMLElement; private getFocusableElements(): HTMLElement[] { return Array.from( this.el.querySelectorAll( 'a[href], button:not([disabled]), input:not([disabled]), select, textarea, [tabindex]:not([tabindex="-1"])' ) ); } @Method() async focusFirst() { const focusable = this.getFocusableElements(); focusable[0]?.focus(); } @Method() async focusLast() { const focusable = this.getFocusableElements(); focusable[focusable.length - 1]?.focus(); } componentDidLoad() { // Access shadow root directly const shadowRoot = this.el.shadowRoot; console.log('Shadow root mode:', shadowRoot?.mode); // "open" // Observe element resizes const observer = new ResizeObserver(entries => { const { width, height } = entries[0].contentRect; console.log(`Component resized to ${width}x${height}`); }); observer.observe(this.el); } render() { return (
); } } ``` -------------------------------- ### Migrate to Percy Source: https://github.com/stenciljs/core/blob/main/docs/screenshot-deprecated.md Demonstrates setting up Percy CLI and Playwright for visual testing. ```typescript // Install Percy npm install --save-dev @percy/cli @percy/playwright // New test with Percy import { test } from '@playwright/test'; import { percySnapshot } from '@percy/playwright'; test('captures button', async ({ page }) => { await page.goto('/button'); await percySnapshot(page, 'Button Component'); }); ``` -------------------------------- ### Stencil CLI Entry Point Source: https://github.com/stenciljs/core/blob/main/docs/cli.md The Node.js executable that bootstraps the Stencil CLI by requiring and running the main CLI module. ```javascript #!/usr/bin/env node 'use strict'; require('../cli/index.js').run(process.argv.slice(2)); ``` -------------------------------- ### createWindowFromHtml Source: https://github.com/stenciljs/core/blob/main/docs/hydrate.md Creates a browser-like window environment from an HTML string, useful for hydrating documents in a Node.js context. ```APIDOC ## createWindowFromHtml ### Description Creates a browser-like window environment from an HTML string. ### Method `createWindowFromHtml(html: string, url: string): Window` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **html** (string) - Required - The HTML string to parse. - **url** (string) - Required - The URL for the window. ### Request Example ```typescript import { createWindowFromHtml } from 'yourpackage/hydrate'; const win = createWindowFromHtml('

Hello

', 'https://example.com'); console.log(win.document.body.innerHTML); ``` ### Response #### Success Response (200) - **Window** - A simulated window object with a document. #### Response Example (Object representing a window environment) ``` -------------------------------- ### Create HTTP Server with Middleware Source: https://github.com/stenciljs/core/blob/main/docs/dev-server.md Sets up the Express HTTP server, including essential middleware like compression, CORS, and JSON body parsing. It also configures request handling and static file serving. ```typescript const createHttpServer = (config: DevServerConfig) => { const app = express(); // Middleware stack app.use(compression()); app.use(cors(config.cors)); app.use(bodyParser.json()); // Request handling app.use(createRequestHandler(config)); // Static file serving app.use(express.static(config.root, { index: false, setHeaders: setCacheHeaders })); return app.listen(config.port, config.address); }; ``` -------------------------------- ### Build Feature Aggregation: Get Build Features Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md Aggregates features across all components to determine the overall build requirements. ```typescript export const getBuildFeatures = (cmps: ComponentCompilerMeta[]): BuildFeatures => { const slot = cmps.some((c) => c.htmlTagNames.includes('slot')); const shadowDom = cmps.some((c) => c.encapsulation === 'shadow'); const slotRelocation = cmps.some((c) => c.encapsulation !== 'shadow' && c.htmlTagNames.includes('slot')); return { allRenderFn: cmps.every(c => c.hasRenderFn), prop: cmps.some(c => c.hasProp), state: cmps.some(c => c.hasState), method: cmps.some(c => c.hasMethod), // ... check every feature across all components }; }; ``` -------------------------------- ### Terser Dead Code Elimination Example Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md Demonstrates how Terser removes code blocks that are conditionally excluded based on the BUILD object. ```typescript // Before if (BUILD.member) { initializeProps(elm, cmpMeta); } // After (when BUILD.member = false) if (false) { initializeProps(elm, cmpMeta); } // Final (removed entirely!) // ... nothing ... ``` -------------------------------- ### Inject Preview Script and HTML Source: https://github.com/stenciljs/core/blob/main/test/browser-compile/src/preview.html Use this code to dynamically inject a script and HTML content into a preview window. The script executes bundled code from the opener, and the HTML content is rendered in the body. ```javascript const script = document.createElement('script'); script.setAttribute('type', 'module'); script.innerHTML = 'console.log("PREVIEW!!");\n' + window.opener.bundledInput; document.head.appendChild(script); document.body.innerHTML = window.opener.htmlCodeInput; ``` -------------------------------- ### Define a Stencil Component Source: https://github.com/stenciljs/core/blob/main/readme.md This example shows how to define a Stencil component using TypeScript decorators. It includes properties and a render method. ```tsx import { Component, Prop, h } from '@stencil/core'; @Component({ tag: 'my-component', styleUrl: 'my-component.css', shadow: true, }) export class MyComponent { @Prop() first: string; @Prop() last: string; render() { return (
Hello, my name is {this.first} {this.last}
); } } ``` -------------------------------- ### History API Fallback Middleware Source: https://github.com/stenciljs/core/blob/main/docs/dev-server.md A middleware for single-page applications that serves 'index.html' for GET requests that accept HTML and do not have a file extension. ```typescript const historyApiFallback = (config) => (req, res, next) => { if (req.method === 'GET' && req.accepts('html') && !req.url.includes('.')) { req.url = '/index.html'; } next(); }; ``` -------------------------------- ### Complex Component Example Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md A feature-rich component utilizing properties, state, events, methods, and Shadow DOM, showcasing the full runtime capabilities. ```typescript @Component({ tag: 'my-form', formAssociated: true, shadow: true, styleUrl: 'my-form.css' }) export class MyForm { @Prop() value: string; @State() isValid = false; @Event() myChange: EventEmitter; @Method() async validate() { // validation logic } @Watch('value') valueChanged() { this.validate(); } render() { // complex render logic } } ``` -------------------------------- ### Opt-in for ES5 and SystemJS Builds Source: https://github.com/stenciljs/core/blob/main/BREAKING_CHANGES.md Configure Stencil to build ES5 and SystemJS files by setting `buildEs5` to 'prod' in the Stencil configuration. This is an opt-in feature for production builds. ```typescript export const config: Config = { buildEs5: 'prod', extras: { cssVarsShim: true, dynamicImportShim: true, safari10: true, shadowDomShim: true, }, }; ``` -------------------------------- ### Create a New Test Suite Directory Source: https://github.com/stenciljs/core/blob/main/test/wdio/README.md Set up a new directory for a WebdriverIO test suite. The directory name should be descriptive of the test's purpose. ```sh mkdir test/wdio/my-excellent-new-test-suite ``` -------------------------------- ### Component Decorators in Stencil Source: https://github.com/stenciljs/core/blob/main/docs/compiler.md Example of a Stencil component using decorators like @Component, @Prop, @State, and @Watch. This code is processed by the Stencil compiler. ```typescript // Your component with decorators @Component({ tag: 'my-component', styleUrl: 'my-component.css', shadow: true }) export class MyComponent { @Prop() name: string; @State() isActive = false; @Watch('name') onNameChange(newValue: string, oldValue: string) { console.log(`Name changed from ${oldValue} to ${newValue}`); } } ``` -------------------------------- ### Visualize Stencil Build Performance Source: https://github.com/stenciljs/core/blob/main/docs/compiler.md A Mermaid diagram illustrating strategies for addressing large bundle sizes in Stencil projects. It suggests checking dependencies, analyzing bundles, and splitting code. ```mermaid graph TD Large[Large Bundle Size] Large --> Check1[Check Dependencies] Check1 --> Tree[Tree Shaking Working?] Check1 --> Imports[Check Import Paths] Large --> Check2[Analyze Bundle] Check2 --> Visualize[Use Bundle Visualizer] Check2 --> FindDups[Find Duplicates] Large --> Check3[Split Code] Check3 --> Lazy[Use Lazy Loading] Check3 --> Dynamic[Dynamic Imports] ``` -------------------------------- ### JSX to h() Compilation Example Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md Illustrates how JSX syntax in a component's render method is compiled into calls to the hyperscript (h) function for creating VNodes. ```typescript // JSX in your component: render() { return (

{this.title}

    {this.items.map(item =>
  • {item.name}
  • )}
); } // Compiles to: render() { return h('div', { class: 'container' }, h('h1', null, this.title), h('button', { onClick: () => this.handleClick() }, 'Click me'), h('ul', null, this.items.map(item => h('li', { key: item.id }, item.name) ) ) ); } ``` -------------------------------- ### Unit Test Stencil Component with `newSpecPage` Source: https://context7.com/stenciljs/core/llms.txt Creates an in-memory rendering environment for unit testing Stencil components. Use `page.waitForChanges()` to flush the async rendering queue after state mutations. ```tsx // src/components/my-button/my-button.spec.tsx import { newSpecPage } from '@stencil/core/testing'; import { MyButton } from './my-button'; describe('MyButton', () => { it('renders with default props', async () => { const page = await newSpecPage({ components: [MyButton], html: ``, }); expect(page.root).toBeDefined(); expect(page.root.shadowRoot.querySelector('button')).not.toBeNull(); }); it('reflects disabled state', async () => { const page = await newSpecPage({ components: [MyButton], html: ``, }); const btn = page.root.shadowRoot.querySelector('button') as HTMLButtonElement; expect(btn.disabled).toBe(true); expect(page.root).toHaveAttribute('disabled'); }); it('increments count on click and emits event', async () => { const page = await newSpecPage({ components: [MyButton], html: ``, }); const emittedEvents: number[] = []; page.root.addEventListener('buttonClicked', (e: CustomEvent) => { emittedEvents.push(e.detail); }); const btn = page.root.shadowRoot.querySelector('button') as HTMLButtonElement; btn.click(); await page.waitForChanges(); btn.click(); await page.waitForChanges(); expect(emittedEvents).toEqual([1, 2]); expect(page.root.shadowRoot.textContent).toContain('(2)'); }); it('calls @Method resetCount', async () => { const page = await newSpecPage({ components: [MyButton], html: ``, }); // Click twice const btn = page.root.shadowRoot.querySelector('button') as HTMLButtonElement; btn.click(); btn.click(); await page.waitForChanges(); // Call the public @Method await (page.root as any).resetCount(); await page.waitForChanges(); expect(page.root.shadowRoot.textContent).toContain('(0)'); }); it('renders using template function', async () => { const page = await newSpecPage({ components: [MyButton], template: () => , }); expect(page.root.getAttribute('label')).toBe('Template'); }); }); ``` -------------------------------- ### Update Dependency Version Ranges Source: https://github.com/stenciljs/core/blob/main/src/testing/jest/README.md Modify the system configuration to set the recommended and maximum versions for Jest and its types. This ensures Stencil installs compatible versions. ```typescript '@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' }, ``` -------------------------------- ### SSR Cross-Component State Example Source: https://github.com/stenciljs/core/blob/main/docs/hydrate.md Demonstrates how components rendered in SSR should not depend on parent state directly. Data should be passed explicitly as props to ensure availability during SSR. ```typescript // ❌ Child won't have access to parent context in SSR // ✅ Pass data explicitly ``` -------------------------------- ### Component Dependency Graph Source: https://github.com/stenciljs/core/blob/main/test/end-to-end/src/slot-parent-cmp/readme.md Visualizes the dependencies between slot-parent-cmp, slot-cmp, and slot-cmp-container using a Mermaid graph. ```mermaid graph TD; slot-parent-cmp --> slot-cmp slot-cmp-container --> slot-parent-cmp style slot-parent-cmp fill:#f9f,stroke:#333,stroke-width:4px ``` -------------------------------- ### SSR Non-Primitive Parameters Example Source: https://github.com/stenciljs/core/blob/main/docs/hydrate.md Illustrates the limitation of using non-primitive parameters with compiler-based SSR. Static data or runtime SSR approaches are recommended for complex objects. ```typescript // ❌ Won't work with compiler-based SSR const menu = generateMenuData(); // ✅ Use static data or runtime SSR const menu = { items: ['Home', 'About'] }; ``` -------------------------------- ### Render a Stencil Component for Testing Source: https://github.com/stenciljs/core/blob/main/test/wdio/README.md Use the `render` helper from `@wdio/browser-runner/stencil` to render a Stencil component within your WebdriverIO tests. No additional imports are needed after the initial setup. ```tsx import { render } from '@wdio/browser-runner/stencil'; render({ template: () => , }); ``` -------------------------------- ### Testing Utilities Source: https://github.com/stenciljs/core/blob/main/docs/testing-deprecated.md Utilize helper functions for testing, including waiting for asynchronous changes, flushing promises, mocking network requests with `mockFetch`, and mocking console output. ```typescript // Wait for async updates await waitForChanges(); // Flush promises await flushPromises(); // Mock fetch mockFetch({ '/api/data': { status: 200, data: { id: 1 } } }); // Mock console const consoleSpy = mockConsole(); ``` -------------------------------- ### Conditional Feature Elimination Source: https://github.com/stenciljs/core/blob/main/docs/runtime.md Shows how Stencil's build optimizer can eliminate code related to features that are not used by any components. Examples include ref handling and key handling. ```typescript // If no components use refs, this code is eliminated if (BUILD.vdomRef && vnode.$attrs$.ref) { vnode.$attrs$.ref(elm); } // If no components use keys, key handling is removed if (BUILD.vdomKey && vnode.$key$) { elm.key = vnode.$key$; } ``` -------------------------------- ### Dev Server Initial Load CSS Source: https://github.com/stenciljs/core/blob/main/src/dev-server/templates/initial-load.html Basic CSS for styling the development server's initial load page, including a toast notification, spinner, and log output area. Supports dark mode. ```css *{ box-sizing: border-box; }html { color-scheme: dark light; }body { position: absolute; padding: 0; margin: 0; width: 100%; height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; }.toast { position: absolute; top: 12px; right: 10px; left: 10px; margin: auto; max-width: 700px; border-radius: 3px; background: rgba(0, 0, 0, .9); -webkit-transform: translate3d(0px, -60px, 0px); transform: translate3d(0px, -60px, 0px); -webkit-transition: -webkit-transform 75ms ease-out; transition: transform 75ms ease-out; pointer-events: none; }.active { -webkit-transform: translate3d(0px, 0px, 0px); transform: translate3d(0px, 0px, 0px); }.content { display: flex; -webkit-align-items: center; -ms-flex-align: center; align-items: center; pointer-events: auto; }.message { -webkit-flex: 1; -ms-flex: 1; flex: 1; padding: 15px; font-size: 14px; color: #fff; }.spinner { position: relative; display: inline-block; width: 56px; height: 28px; }svg:not(:root) { overflow: hidden; }svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-transform: translateZ(0); transform: translateZ(0); -webkit-animation: rotate 600ms linear infinite; animation: rotate 600ms linear infinite; }@-webkit-keyframes rotate { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }@keyframes rotate { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }svg circle { fill: transparent; stroke: white; stroke-width: 4px; stroke-dasharray: 128px; stroke-dashoffset: 82px; }.logs { position: absolute; top: 50px; right: 10px; left: 10px; margin: auto; max-width: 700px; padding: 32px; line-height: 1.5; }@media (prefers-color-scheme: dark) { .toast { background: rgb(49, 49, 49, .9); }} ``` -------------------------------- ### Methods Source: https://github.com/stenciljs/core/blob/main/test/end-to-end/src/resolve-var-events/readme.md This section describes the methods available for emitting events. ```APIDOC ## Methods ### `emitMyEvent()` #### Returns - **Type**: `Promise` ### `emitOtherEvent()` #### Returns - **Type**: `Promise` ``` -------------------------------- ### Run Stencil CLI Unit Tests Source: https://github.com/stenciljs/core/blob/main/docs/cli.md Execute unit tests for the Stencil CLI using npm test, targeting the src/cli directory. ```bash npm test src/cli ``` -------------------------------- ### Hydrate Document with Options Source: https://github.com/stenciljs/core/blob/main/docs/hydrate.md Use `hydrateDocument` to hydrate a DOM document and get hydrated HTML. Pass options like `url`, `userAgent`, `cookie`, `direction`, and `language` for context. ```typescript import { hydrateDocument, createWindowFromHtml } from 'yourpackage/hydrate'; export async function hydrateComponents(template: string) { const win = createWindowFromHtml(template, Math.random().toString()) const results = await hydrateDocument(win.document, { url: 'https://example.com', userAgent: 'Node.js', cookie: 'session=abc123', direction: 'ltr', language: 'en', }); return results.html; } ``` -------------------------------- ### Stencil Compiler Integration Test Source: https://github.com/stenciljs/core/blob/main/docs/compiler.md An example of an integration test for the Stencil compiler. It uses the 'compile' function to build a component and asserts that no errors occurred and the correct number of components were compiled. ```typescript describe('compiler', () => { it('should compile component', async () => { const results = await compile({ srcDir: './test/fixtures' }); expect(results.hasError).toBe(false); expect(results.components).toHaveLength(1); }); }); ``` -------------------------------- ### Move mockDocument and mockWindow to @stencil/core/testing Source: https://github.com/stenciljs/core/blob/main/BREAKING_CHANGES.md The mockDocument and mockWindow functions have been moved from '@stencil/core/mock-dom' to '@stencil/core/testing'. Update your import paths accordingly. ```diff - import { mockDocument, mockWindow } from '@stencil/core/mock-dom'; + import { mockDocument, mockWindow } from '@stencil/core/testing'; ``` -------------------------------- ### Programmatic Build API with Stencil Compiler Source: https://context7.com/stenciljs/core/llms.txt Utilizes Stencil's programmatic API for custom build scripts and tooling. Demonstrates loading configuration, creating a compiler instance for one-shot builds, and setting up a watcher for incremental rebuilds. ```typescript import { createNodeLogger, createNodeSys } from '@stencil/core/sys/node'; import { loadConfig, createCompiler } from '@stencil/core/compiler'; async function buildComponents() { const logger = createNodeLogger({ level: 'info' }); const sys = createNodeSys({ process }); // Load and validate stencil.config.ts const loadResult = await loadConfig({ configPath: './stencil.config.ts', config: { flags: { prod: true, ci: true }, }, logger, sys, }); if (loadResult.diagnostics.some(d => d.level === 'error')) { logger.error('Config errors:', loadResult.diagnostics); process.exit(2); } const compiler = await createCompiler(loadResult.config); // One-shot production build const results = await compiler.build(); console.log(`Build ${results.hasError ? 'FAILED' : 'succeeded'} in ${results.duration}ms`); console.log(`Components: ${results.componentGraph?.size ?? 0}`); console.log(`Files written: ${results.filesWritten}`); if (results.diagnostics.length) { results.diagnostics.forEach(d => { const fn = d.level === 'error' ? logger.error : logger.warn; fn(`[${d.type}] ${d.messageText} (${d.relFilePath}:${d.lineNumber})`); }); } await compiler.destroy(); if (results.hasError) process.exit(1); } // Watch mode usage async function watchComponents() { const { config } = await loadConfig({ configPath: './stencil.config.ts' }); const compiler = await createCompiler(config); const watcher = await compiler.createWatcher(); watcher.on('buildFinish', results => { console.log(`Rebuild finished in ${results.duration}ms`); }); watcher.on('buildLog', log => { console.log(log.messages.join('\n')); }); // Graceful shutdown process.on('SIGINT', async () => { await watcher.close(); await compiler.destroy(); }); } buildComponents().catch(console.error); ``` -------------------------------- ### Angular ng-if Example Source: https://github.com/stenciljs/core/blob/main/test/wdio/slot-ng-if/index.html This snippet shows how to use the ng-if directive to conditionally render an element based on a scope variable. Ensure the 'demo' module and 'homeCtrl' controller are properly set up. ```html
{{vm.label}}
This is shown when vm.show is true
``` ```javascript angular.module('demo', []).controller('homeCtrl', homeCtrl); function homeCtrl() { var vm = this; vm.label = 'Angular Bound Label'; vm.show = true; } angular.bootstrap(document.querySelector('#demo'), ['demo']); ``` -------------------------------- ### Prerendering Configuration Source: https://github.com/stenciljs/core/blob/main/docs/compiler.md Configuration object for prerendering, specifying entry URLs and hydrate options such as timeout and static components. Enables static site generation at build time. ```typescript const prerenderConfig = { entryUrls: ['/'], hydrateOptions: { timeout: 10000, staticComponents: ['app-header', 'app-footer'] } }; ``` -------------------------------- ### Define Copy Task in Output Target Source: https://github.com/stenciljs/core/blob/main/test/copy-task/README.md Configure a copy task within an output target to specify source and destination directories. This example shows how to copy files from './utils' to './dist/utilsExtra'. ```typescript { type: 'dist-custom-elements', copy: [{ src: './utils', dest: './dist/utilsExtra', }] } ```