shopware / shopware/shopware

Storefront component import map does not strip trailing `index` for anonymous UX components

Open
#18,455 0 comments 0 reactions 1 assignee Claimed by @BrocksiNet View on GitHub
component/storefront domain/discovery priority/low
Dominant language
PHP
Stars
3.4k
Forks
1.2k
Avg merge
3d 55m
Merged PRs (30d)
436

Description

### PHP Version

8.3+

### Shopware Version

6.7.12.1

### Expected behaviour

According to the component-system docs
([Directory Structure & Component Script Loading](https://github.com/shopware/shopware/tree/trunk/src/Storefront/Resources/app/storefront/src/component-system#directory-structure--component-script-loading)),
anonymous/index component layout should resolve to the **directory name** as the component name — same as the flat layout.

Both of these should produce the JS import-map specifier / `data-component` name
`MyNamespace:MyComponent`:

```
views/components/MyNamespace/MyComponent.html.twig
views/components/MyNamespace/MyComponent.js
```

```
views/components/MyNamespace/MyComponent/index.html.twig
views/components/MyNamespace/MyComponent/index.js
```

Runtime should load the built module via the import map when the template uses:

```html


```

### Actual behaviour

With the index layout, the Vite entry / import-map tag **keeps** the trailing `index` segment:

- Vite manifest `name`: `MyNamespace/MyComponent/index`
- Import map key: `MyNamespace:MyComponent:index`
- Template / Twig component name: `MyNamespace:MyComponent`

`Shopware.getComponent('MyNamespace:MyComponent')` does not find a match in the import map, falls back to the bare specifier, and the browser tries to fetch `mynamespace:MyComponent` as a custom URL scheme, which surfaces as:

```
Access to script at 'mynamespace:MyComponent' from origin '…' has been blocked by CORS policy
Failed to import component MyNamespace:MyComponent: TypeError: Failed to fetch dynamically imported module
```

This is misleading: the real failure is a **missing import-map entry**, not CORS.

Twig anonymous components work (directory name = component name). Only the **JS/CSS build + import-map aggregation** path fails to strip `/index`.

### How to reproduce

1. Create an extension component using index naming, e.g.:

```
Resources/views/components/Demo/Search/Action/index.html.twig
Resources/views/components/Demo/Search/Action/index.js
```

2. In the template:

```twig

```

```js
// index.js
export default class SearchAction extends ShopwareComponent {
init() { console.log('ok'); }
}
```

3. Build components and refresh theme assets/import map
(`composer build:js:storefront` / theme compile / asset install as applicable).

4. Load a storefront page that renders the component.

5. Observe console: bare-specifier fetch + failed dynamic import for `Demo:Search:Action`.

6. Inspect Vite `build-meta.json` / manifest: entry name is `Demo/Search/Action/index` → import map key `Demo:Search:Action:index`.

### Root cause (code)

Import-map tags are derived from the Vite entry name with a simple `/` → `:` replace and **no** trailing `index` normalization:

- `src/Storefront/Resources/app/storefront/build/vite/build-components.js` — `makeJsEntryName` keeps `…/index`
- `src/Storefront/Resources/app/storefront/build/vite/component-config-factory.ts` — same
- `src/Storefront/Resources/app/storefront/build/vite/dev-import-map-plugin.ts` — `fileToTag()` does not strip `/index`
- `src/Storefront/Theme/ThemeCompiler.php` (`readBundleComponentManifest`) —
`$tag = str_replace('/', ':', $entryName);` does not strip `/index`

Docs already describe the intended behaviour; implementation does not match.

### Suggested fix

Normalize entry names / tags by stripping a trailing `/index` (and `.scss`/`.css` variants consistently) in:

1. JS entry naming (`makeJsEntryName` / style entry helpers)
2. Dev import map `fileToTag()`
3. Optionally `ThemeCompiler` as a safety net for already-built manifests

After fix, index layout should map to `Namespace:Component` (not `Namespace:Component:index`).

### Workaround

Use flat file naming instead of index directories for co-located JS/SCSS:

```
MyComponent.js + MyComponent.html.twig
```

instead of

```
MyComponent/index.js + MyComponent/index.html.twig
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.