# General Translation Integrations: Resolving imports
URL: https://generaltranslation.com/en-GB/docs/integrations/paraglide/guides/resolving-imports.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: How to make the analysis follow your app's import aliases to its Paraglide JS files.

An import counts as Paraglide JS only when it resolves to a Paraglide JS file. An alias the analysis does not know, such as `~/paraglide/messages.js`, hides every usage behind it. Use this guide when a run warns about unresolved imports or finds fewer usages than you expect.

## Check where aliases come from [#alias-sources]

Imports are resolved like your bundler would resolve them, without running it. Aliases come from these sources, in order:

1. The [`alias`](/docs/integrations/paraglide/reference/collect-context#alias) option.
2. The first `vite.config.*`, `webpack.config.*`, or `rspack.config.*` found in the root directory or the project root.
3. `paths` in `tsconfig.json` and `imports` in `package.json`.

The bundler configs are read differently:

* **Vite:** your project&#39;s own Vite resolves the config, so aliases that plugins add (SvelteKit&#39;s `$lib`) and root paths (`/src/a.js`) work.
* **webpack and rspack:** the config file is imported. Exact-match (`name$`) and wildcard (`"@/*"`) aliases work. A TypeScript config needs a Node.js version that runs TypeScript.

Next.js, Nuxt, and Astro configs are not read. Their aliases come from `tsconfig.json`.

## Declare an alias [#declare-alias]

Add an alias that no config declares, or override one. Your own aliases are matched before the config&#39;s.

<Tabs items={['CLI', 'Library']}>
  <Tab value="CLI">
    ```bash
    # A relative replacement resolves from the project root
    npx paraglide-context --alias ~=./src --alias @ui=./packages/ui/src
    ```
  </Tab>

  <Tab value="Library">
    ```ts
    import path from 'node:path';
    import { collectContext } from '@generaltranslation/paraglide-js/compiler';

    await collectContext({
      // Replacements are absolute paths
      alias: { '~': path.resolve('src') },
    });
    ```
  </Tab>
</Tabs>

## Fix unresolved imports [#unresolved]

When no bundler config could be read, the run ends with a warning that lists the imports that did not resolve, since they may be undeclared aliases. For each one:

1. Declare it with `--alias`, or add it to `paths` in `tsconfig.json`.
2. Run `paraglide-context --verbose` again. The summary names the config the aliases were read from.

If a bundler config exists but breaks when it is loaded outside a build, skip it with `--no-bundler-config` and declare the aliases yourself.

## Read another bundler&#39;s config [#bundler-config]

Add a [`BundlerConfig`](/docs/integrations/paraglide/reference/extension-api#bundler-configs) to read aliases from a config the defaults do not cover. [`webpackLikeConfig`](/docs/integrations/paraglide/reference/extension-api#bundler-configs) makes one for a file in webpack&#39;s format:

```ts
import {
  collectContext,
  defaultBundlerConfigs,
  webpackLikeConfig,
} from '@generaltranslation/paraglide-js/compiler';

await collectContext({
  bundlerConfigs: [
    ...defaultBundlerConfigs,
    // Reads resolve.alias from webpack.prod.js, .mjs, .ts, …
    webpackLikeConfig('webpack (production)', 'webpack.prod'),
  ],
});
```

For any other format, write the `read` function yourself:

```ts
import { readFile } from 'node:fs/promises';
import {
  collectContext,
  defaultBundlerConfigs,
  type BundlerConfig,
} from '@generaltranslation/paraglide-js/compiler';

const aliasFile: BundlerConfig = {
  name: 'aliases.json',
  files: ['aliases.json'], // looked for in the root and the project root
  async read(file) {
    // { "~": "/app/src" }
    const entries = Object.entries(JSON.parse(await readFile(file, 'utf8')));

    return {
      aliases: entries.map(([find, replacement]) => ({
        find,
        replacement: String(replacement),
      })),
    };
  },
};

await collectContext({ bundlerConfigs: [...defaultBundlerConfigs, aliasFile] });
```

Only the first config found is read. A `read` that fails is reported in a warning and the config is skipped.

## Use another resolver [#custom-resolver]

To replace import resolution entirely, create the collector yourself and pass it a [`Resolver`](/docs/integrations/paraglide/reference/extension-api#resolvers): a function that returns the file an import resolves to, or nothing.

```ts
import {
  createCollector,
  nodeResolver,
} from '@generaltranslation/paraglide-js/compiler';

const fallback = nodeResolver();

const collector = createCollector(
  { include: ['src'] },
  {
    root: process.cwd(),
    logger: console,
    resolver: async (specifier, importer) =>
      specifier === 'virtual:messages'
        ? '/app/src/paraglide/messages.js'
        : fallback(specifier, importer),
  }
);

await collector.scanAll(); // analyse
await collector.write(); // write the metadata files
```

## What to use and when [#what-to-use]

* **`--alias` or `alias`:** a few aliases no config declares.
* **`tsconfig.json` `paths`:** aliases your editor and type checker should also know.
* **A `BundlerConfig`:** aliases that already live in a config file of another bundler.
* **A `Resolver`:** resolution that aliases cannot express, such as virtual modules.

## Next steps

- /docs/integrations/paraglide/guides/adding-file-formats

## Sitemap

See the full [sitemap](https://generaltranslation.com/sitemap.md) for all pages.
