The Scripts directory contains the build system used to develop and build Stencil itself. This is separate from Stencil's compiler that builds user projects - this is specifically for building the Stencil compiler and its related modules.
Location: scripts/
The build system uses esbuild as its primary bundler to create all the distributable packages that make up Stencil. It handles bundling, minification, TypeScript compilation, and packaging of various Stencil components.
graph TD
subgraph "Build Entry"
Entry[scripts/index.ts] --> BuildRunner[build.ts]
end
subgraph "Build Tasks"
BuildRunner --> CLI[buildCli]
BuildRunner --> Compiler[buildCompiler]
BuildRunner --> DevServer[buildDevServer]
BuildRunner --> MockDoc[buildMockDoc]
BuildRunner --> Internal[buildInternal]
BuildRunner --> Testing[buildTesting]
BuildRunner --> SysNode[buildSysNode]
BuildRunner --> Screenshot[buildScreenshot]
end
subgraph "Bundled Dependencies"
Compiler --> TypeScript[TypeScript Bundle]
Compiler --> Terser[Terser Bundle]
Compiler --> Parse5[Parse5 Bundle]
end
scripts/
├── build.ts # Main build orchestrator
├── index.ts # Entry point
├── release.ts # Release automation
├── release-tasks.ts # Release task definitions
├── tsconfig.json # TypeScript config for scripts
├── updateSelectorEngine.ts # Playwright selector engine updater
│
├── esbuild/ # ESBuild configurations
│ ├── cli.ts # CLI bundle config
│ ├── compiler.ts # Compiler bundle config
│ ├── dev-server.ts # Dev server bundle config
│ ├── internal.ts # Internal packages bundle config
│ ├── mock-doc.ts # Mock DOM bundle config
│ ├── screenshot.ts # Screenshot bundle config
│ ├── sys-node.ts # Node system bundle config
│ ├── testing.ts # Testing bundle config
│ └── utils/ # Build utilities
│ ├── typescript-source.ts
│ ├── terser.ts
│ ├── parse5.ts
│ └── ...
│
├── utils/ # General utilities
│ ├── options.ts # Build options
│ ├── banner.ts # File banners
│ ├── bundle-dts.ts # TypeScript declarations bundler
│ └── ...
│
└── test/ # Build validation
└── validate-build.ts # Post-build validation
Location: scripts/index.ts
The build starts here when running npm run build:
const stencilProjectRoot = join(__dirname, '..');
const args = process.argv.slice(2);
build.run(stencilProjectRoot, args);Location: scripts/build.ts
The main build runner that coordinates all build tasks:
export async function buildAll(opts: BuildOptions) {
await Promise.all([
buildCli(opts),
buildCompiler(opts),
buildDevServer(opts),
buildMockDoc(opts),
buildScreenshot(opts),
buildSysNode(opts),
buildTesting(opts),
buildInternal(opts),
]);
}All builds run in parallel for maximum efficiency.
Location: scripts/utils/options.ts
Build configuration is centralized:
- Version management
- Directory paths
- Build flags (prod, CI, watch)
- Dependency versions
Stencil bundles several key dependencies directly into its output to ensure consistency and avoid version conflicts:
Location: scripts/esbuild/utils/typescript-source.ts
TypeScript is bundled and patched:
- The TypeScript compiler is read from
node_modules - Object.defineProperty calls are modified to be configurable
- The result is cached for faster rebuilds
// TypeScript properties need to be configurable for our patches
const TS_PROP_DEFINER = `__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true // Added by Stencil
});`;Location: scripts/esbuild/utils/terser.ts
Terser is bundled for JavaScript minification:
- Used in production builds
- Cached based on version
- Provides consistent minification across environments
Location: scripts/esbuild/utils/parse5.ts
Parse5 is bundled for HTML parsing:
- Used by mock-doc for server-side rendering
- Bundled with Rollup (legacy from previous build system)
- Version-specific caching
Each build task creates a specific output package:
- Main Stencil compiler
- Includes bundled TypeScript, Terser, and Parse5
- Entry:
stencil.js
- Command-line interface
- Both ESM and CommonJS builds
- Entry:
index.js/index.cjs
- Development server with HMR
- Includes WebSocket server
- Entry:
index.js
- Shared internal modules
- Client runtime
- Hydrate platform
- App data/globals
- Server-side DOM implementation
- Includes bundled Parse5
- Entry:
index.cjs/index.js
- Jest integration
- Testing utilities
- Entry:
index.js
- Node.js system abstraction
- File system operations
- Entry:
index.js
- Visual regression testing (deprecated)
- Entry:
index.js
Location: scripts/esbuild/utils/index.ts
Common settings for all bundles:
{
bundle: true,
format: 'esm' | 'cjs',
platform: 'node',
target: ['node16'],
sourcemap: 'external',
minify: isProd,
logLevel: 'info'
}Path aliases are used extensively:
@platform→ Platform-specific code@utils→ Shared utilities@app-data→ Build conditionals@sys-api-node→ Node system API
Most Node.js dependencies are externalized except:
- TypeScript (bundled)
- Terser (bundled)
- Parse5 (bundled)
# Development build
npm run build
# Production build
npm run build -- --prod
# Watch mode
npm run build -- --watch
# Validate build
npm run build -- --validate-buildThe build system implements several caching strategies:
- TypeScript Bundle Cache: Based on TypeScript version
- Terser Bundle Cache: Based on Terser version
- Parse5 Bundle Cache: Based on Parse5 version
- DTS Bundle Cache: For TypeScript declarations
In watch mode, only changed files trigger rebuilds of affected bundles.
Location: scripts/release-tasks.ts
Automated release process:
- Validate version
- Install dependencies
- Build TypeScript (
tsc.prod) - Bundle all packages
- Update changelog
- Publish to npm
- Tag git commit
Versions can be:
- Semantic version words:
major,minor,patch - Explicit versions:
4.0.0 - Pre-release versions:
4.0.0-beta.1
Location: scripts/test/validate-build.ts
Post-build validation ensures:
- All expected files exist
- Package.json files are correct
- TypeScript declarations compile
- Tree-shaking works properly
- No unexpected dependencies
The TypeScript bundling process patches TypeScript to:
- Make properties configurable for monkey-patching
- Enable in-memory file system usage
- Support custom transformers
The build carefully manages module loading order to avoid circular dependencies between packages.
Different bundles for:
- Node.js environments (compiler, CLI)
- Browser environments (client runtime)
- Hybrid environments (testing, dev server)
- Build Performance: Investigate faster bundling strategies
- Dependency Updates: Automate bundled dependency updates
- Build Analytics: Add timing and size tracking
- Cache Management: Smarter cache invalidation
- Monorepo Structure: Consider splitting into separate packages