A codemod that migrates Ember projects from ember-svg-jar to direct SVG component imports.
The codemod finds all {{svgJar "..."}} mustache calls in your .gjs and .gts files and replaces them with angle-bracket component invocations backed by direct SVG imports.
Before:
import svgJar from 'ember-svg-jar/helpers/svg-jar';
<template>
{{svgJar "arrow-right" class="icon"}}
{{svgJar "#star" class="star-icon"}}
</template>After:
import ArrowRight from '../../public/icons/arrow-right.svg?unsafe-inline';
import Star from '../../public/icons/star.svg';
<template>
<ArrowRight class="icon" />
<Star class="star-icon" />
</template>- Reads your
ember-cli-build.js(or.mjs/.cjs) to find configuredsvgJar.sourceDirs - Discovers all
.gjs/.gtstemplate files in the project - For each
{{svgJar "icon-name"}}call, locates the SVG file on disk - Replaces the mustache with a
<ComponentName />invocation, preserving all attributes - Adds an import statement with the correct relative path to the SVG file
- Removes the
ember-svg-jarimport when all icons in a file are resolved
The codemod generates import paths relative to the file being transformed:
app/components/navbar.gjs → ../../public/icons/menu.svg?unsafe-inline
app/templates/settings/index.gts → ../../../public/icons/settings.svg?unsafe-inline
If your package.json defines subpath imports that match a source directory, the codemod uses those instead:
{
"imports": {
"#icons/*": "./public/icons/*"
}
}// Uses alias instead of relative path
import Menu from '#icons/menu.svg?unsafe-inline';- Inline icons (
{{svgJar "icon"}}) get the?unsafe-inlinequery suffix - Sprite icons (
{{svgJar "#icon"}}) use a plain import path (no suffix) - When the same slug appears as both inline and sprite, the sprite keeps the plain name (
Icon) and the inline variant gets anInlinesuffix (IconInline)
pnpm dlx @svg-jar/codemodRuns the codemod on the current directory. In interactive mode, you'll be prompted before writing changes.
pnpm dlx @svg-jar/codemod app/componentsOnly processes files under app/components/. The project root is inferred from the app/ segment in the path.
pnpm dlx @svg-jar/codemod app/components/navbar.gjsTransforms only the specified file. The project root is inferred and you'll be prompted to confirm it.
pnpm dlx @svg-jar/codemod /path/to/my-ember-app| Flag | Description |
|---|---|
-d, --dry-run |
Preview changes without writing to disk |
-c, --confirm |
Pause after each file and ask to continue |
-V, --version |
Print the version number |
-h, --help |
Show help |
pnpm dlx @svg-jar/codemod --dry-runShows which files would be changed and reports any issues without modifying anything.
pnpm dlx @svg-jar/codemod --confirmPauses after each file is processed and asks "Continue to next file?". Useful for reviewing changes one at a time.
After the run completes, the codemod prints an ESLint-style report for any issues found:
app/components/broken-component.gjs
5 warning Icon "nonexistent-icon" not found in any source directory
app/components/ambiguous.gjs
8 warning Icon "arrow" found in multiple source directories
- public/icons/arrow.svg
- vendor/icons/arrow.svg
2 warnings (1 unresolved, 1 ambiguous)
8 files changed out of 10 scanned
- Unresolved icons - the SVG file was not found in any source directory. The
{{svgJar ...}}call is left unchanged and theember-svg-jarimport is kept. - Ambiguous icons - the SVG file exists in multiple source directories. The first match is used, but you should verify the correct one was chosen.
The codemod can also be used as a library:
import { run } from '@svg-jar/codemod';
const { output, unresolvedIcons, ambiguousIcons } = run(source, filePath, {
projectRoot: '/path/to/project',
});For more control, use transform() directly with pre-computed configuration:
import { transform } from '@svg-jar/codemod';
const result = transform(source, filePath, {
projectRoot: '/path/to/project',
sourceDirs: ['public/icons'],
importAliases: [],
});- Node.js >= 20
- Ember projects using
.gjsor.gtstemplate files - Icons must exist as
.svgfiles in the configured source directories
The codemod reads configuration from your existing project files:
ember-cli-build.js(or.mjs/.cjs) --svgJar.sourceDirsdetermines where to look for SVG files. Defaults to['public']if not configured.package.json--importsfield entries matching source directories are used as import aliases.