diff --git a/BREAKING.md b/BREAKING.md
index 8bb2a136313..ba6c2e1d001 100644
--- a/BREAKING.md
+++ b/BREAKING.md
@@ -15,6 +15,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
## Version 9.x
- [Browser and Platform Support](#version-9x-browser-platform-support)
+- [Package Exports](#version-9x-package-exports)
- [Components](#version-9x-components)
- [Legacy Picker](#version-9x-legacy-picker)
- [Router Outlet](#version-9x-router-outlet)
@@ -32,6 +33,23 @@ This section details the desktop browser, JavaScript framework, and mobile platf
| --------- | --------------------- |
| React | 18+ |
+
Package Exports
+
+`@ionic/core`'s `package.json` now declares an `exports` field. Subpaths like `@ionic/core/components` and `@ionic/core/loader` previously failed under Node ESM (Angular 21's default Vitest builder, raw Node, etc.) with `ERR_UNSUPPORTED_DIR_IMPORT`, because the strict ESM resolver doesn't read the nested `package.json` files this package relied on. The new `exports` map declares the documented subpaths explicitly.
+
+`exports` is an allowlist. Apps using Node ESM, webpack 5, or TypeScript `moduleResolution: "bundler"`/`"node16"`/`"nodenext"` that import from undocumented internal paths need to switch to one of the supported subpaths:
+
+| Subpath | Use |
+| ---------------------------------- | ----------------------------------------------------- |
+| `@ionic/core` | Root entry, controllers, animation builders |
+| `@ionic/core/components` | Custom-element constructors and shared utilities |
+| `@ionic/core/components/ion-*.js` | Single-component custom-element constructor |
+| `@ionic/core/loader` | `defineCustomElements` lazy loader |
+| `@ionic/core/hydrate` | SSR hydration entry |
+| `@ionic/core/css/*.css` | Global stylesheets and palettes |
+
+Apps on `moduleResolution: "node"` (classic) and webpack 4 keep resolving through the legacy fields and are unaffected.
+
Components
Legacy Picker
diff --git a/core/package-lock.json b/core/package-lock.json
index 994c89ecb8e..4e682aa8987 100644
--- a/core/package-lock.json
+++ b/core/package-lock.json
@@ -95,7 +95,6 @@
"version": "7.16.12",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.8",
@@ -635,7 +634,6 @@
"integrity": "sha512-CqRQCkb6HXxcx/N7s+hHTN6ef2CmamFiRMITwm4qB840ph56mS42bzUgn6tKCP+RZjdDweiRHj9ytDDeN6jFag==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -861,7 +859,6 @@
"version": "4.33.0",
"dev": true,
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "4.33.0",
"@typescript-eslint/types": "4.33.0",
@@ -1815,7 +1812,6 @@
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.43.0.tgz",
"integrity": "sha512-6Uj2Z3lzLuufYAE7asZ6NLKgSwsB9uxl84Eh34PASnUjfj32GkrP4DtKK7fNeh1WFGGyffsTDka3gwtl+4reUg==",
"license": "MIT",
- "peer": true,
"bin": {
"stencil": "bin/stencil"
},
@@ -2313,7 +2309,6 @@
"version": "6.7.2",
"dev": true,
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "6.7.2",
"@typescript-eslint/types": "6.7.2",
@@ -2539,6 +2534,7 @@
"integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/shared": "3.5.25",
@@ -2553,6 +2549,7 @@
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"license": "BSD-2-Clause",
+ "peer": true,
"engines": {
"node": ">=0.12"
},
@@ -2565,7 +2562,8 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.25",
@@ -2573,6 +2571,7 @@
"integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/compiler-core": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2584,6 +2583,7 @@
"integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/compiler-core": "3.5.25",
@@ -2601,7 +2601,8 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@vue/compiler-sfc/node_modules/postcss": {
"version": "8.5.6",
@@ -2623,6 +2624,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -2638,6 +2640,7 @@
"integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2649,6 +2652,7 @@
"integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/shared": "3.5.25"
}
@@ -2659,6 +2663,7 @@
"integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/reactivity": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2670,6 +2675,7 @@
"integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/reactivity": "3.5.25",
"@vue/runtime-core": "3.5.25",
@@ -2683,6 +2689,7 @@
"integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/compiler-ssr": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2696,7 +2703,8 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz",
"integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@zeit/schemas": {
"version": "2.21.0",
@@ -2719,7 +2727,6 @@
"version": "7.4.0",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3889,7 +3896,8 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/debug": {
"version": "2.6.9",
@@ -4183,7 +4191,6 @@
"version": "7.32.0",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.4.3",
@@ -7569,6 +7576,7 @@
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
@@ -7906,6 +7914,7 @@
}
],
"license": "MIT",
+ "peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -8269,7 +8278,6 @@
"integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"playwright-core": "cli.js"
},
@@ -8281,7 +8289,6 @@
"version": "7.0.35",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
@@ -8387,7 +8394,6 @@
"version": "0.36.2",
"dev": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"postcss": ">=5.0.0"
}
@@ -8436,7 +8442,6 @@
"version": "2.6.1",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"prettier": "bin-prettier.js"
},
@@ -8839,7 +8844,6 @@
"version": "2.35.1",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -8905,7 +8909,8 @@
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/semver": {
"version": "5.7.1",
@@ -9068,6 +9073,7 @@
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
diff --git a/core/package.json b/core/package.json
index 7fada6e1abc..04ba0feb03d 100644
--- a/core/package.json
+++ b/core/package.json
@@ -26,6 +26,38 @@
"collection:main": "dist/collection/index.js",
"collection": "dist/collection/collection-manifest.json",
"types": "dist/types/interface.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/types/interface.d.ts",
+ "import": "./dist/index.js",
+ "require": "./dist/index.cjs.js",
+ "default": "./dist/index.js"
+ },
+ "./components": {
+ "types": "./components/custom-elements.d.ts",
+ "import": "./components/index.js",
+ "default": "./components/index.js"
+ },
+ "./components/*": "./components/*",
+ "./loader": {
+ "types": "./loader/index.d.ts",
+ "import": "./loader/index.js",
+ "require": "./loader/index.cjs.js",
+ "default": "./loader/index.js"
+ },
+ "./loader/*": "./loader/*",
+ "./hydrate": {
+ "types": "./hydrate/index.d.ts",
+ "import": "./hydrate/index.mjs",
+ "require": "./hydrate/index.js",
+ "default": "./hydrate/index.js"
+ },
+ "./hydrate/*": "./hydrate/*",
+ "./css/*.css": "./css/*.css",
+ "./css/*": "./css/*",
+ "./dist/*": "./dist/*",
+ "./package.json": "./package.json"
+ },
"files": [
"components/",
"css/",