analog icon indicating copy to clipboard operation
analog copied to clipboard

`Failed to resolve import "angular:jit:template:file;./app.component.html"` error when plugin is loaded twice and jit is enabled

Open yjaaidi opened this issue 1 year ago • 1 comments

Please provide the environment you discovered this bug in.

Running vitest while loading the angular plugin twice in jit mode fails.

import angular from '@analogjs/vite-plugin-angular';

export default defineConfig(({ mode }) => {
  return {
    plugins: [
      angular({jit: true}),
      angular({jit: true})
    ],
    ...
  }
});

This is a black swan edge case that should almost never happen but when it happens it is really hard to debug. I just spent few hours due to an issue with Nx vitest executor which extracts the plugins from the vite config and gives it back to vitest causing the plugins to be loaded twice 😅

Which area/package is the issue in?

vitest-angular

Description

When @analogjs/vite-plugin-angular is loaded twice in vite config and jit mode is enabled the following error happens:

Error: Failed to resolve import "angular:jit:template:file;./app.component.html" from "src/app/app.component.ts". Does the file exist?

Please provide the exception or error you saw

No response

Other information

This seems to happen because the templateUrl is extracted from the source code instead of the TS output.

https://github.com/analogjs/analog/blob/7091444b068e964e5f1f2a94f5298ee38d7e2df3/packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts#L320

I guess that this could be fixed by extracting the template URLs from the transformed data:

https://github.com/analogjs/analog/blob/7091444b068e964e5f1f2a94f5298ee38d7e2df3/packages/vite-plugin-angular/src/lib/angular-vite-plugin.ts#L347

Please let me know if this fix works for you or do you suggest a better alternative?

I would be willing to submit a PR to fix this issue

  • [X] Yes
  • [ ] No

yjaaidi avatar Aug 21 '24 23:08 yjaaidi

If we can reliably extract the template and style URLs from the compiled output, that seems reasonable to me.

brandonroberts avatar Aug 23 '24 00:08 brandonroberts

got that error when: angular library has vite.config.mts for vitest has storybook and try to use it with vite

when run storybook dev got that type of error. When I delete vite.config.mts storybook working properly

pumano avatar Dec 10 '24 14:12 pumano

Landed a fix. It can be tested in 1.10.2-beta.4

brandonroberts avatar Dec 10 '24 16:12 brandonroberts

@brandonroberts I try 1.10.2-beta.4 with no luck.

Looks like problem with merging configs from storybook vite final where angular() plugin and vite.config.ts where plugin exist too:

warn - https://tailwindcss.com/docs/content-configuration
10:20:16 PM [vite] Pre-transform error: Failed to resolve import "angular:jit:template:file;./ui-kit.component.html" from "src/lib/ui-kit/ui-kit.component.ts". Does the file exist?
10:20:16 PM [vite] Internal server error: Failed to resolve import "angular:jit:template:file;./ui-kit.component.html" from "src/lib/ui-kit/ui-kit.component.ts". Does the file exist?
  Plugin: vite:import-analysis
  File: /Users/iam/myorg/my-app/libs/ui-kit/src/lib/ui-kit/ui-kit.component.ts:2:35
  1  |  import { __decorate } from "tslib";
  2  |  import __NG_CLI_RESOURCE__0 from "angular:jit:template:file;./ui-kit.component.html";
     |                                    ^
  3  |  import __NG_CLI_RESOURCE__1 from "angular:jit:style:file;./ui-kit.component.css";
  4  |  import { Component } from '@angular/core';
      at TransformPluginContext._formatError (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:49255:41)
      at TransformPluginContext.error (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:49250:16)
      at normalizeUrl (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:64041:23)
      at async file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:64173:39
      at async Promise.all (index 1)
      at async TransformPluginContext.transform (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:64100:7)
      at async PluginContainer.transform (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:49096:18)
      at async loadAndTransform (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:51929:27)
      at async viteTransformMiddleware (file:///Users/iam/myorg/my-app/node_modules/vite/dist/node/chunks/dep-CB_7IfJ-.js:61881:24)
10:21:24

steps to reproduce:

  1. create fresh nx integrated project with angular (via nx)
  2. create angular nx library (buildable) for example "ui-kit" in "libs" folder with unit testing vitest (via nx console)
  3. create storybook setup for that lib (via nx console)
  4. update storybook with "vite final" as recommended at analogjs website

run cd libs/ui-kit run npx storybook dev --port 4400

pumano avatar Dec 10 '24 19:12 pumano

Thanks @pumano. Storybook isn't supposed to load the config if the viteConfigPath is set to undefined. Will take a look

brandonroberts avatar Dec 10 '24 20:12 brandonroberts

If you just return the config directly instead of merging, does it work?

brandonroberts avatar Dec 10 '24 20:12 brandonroberts

@brandonroberts if I just delete angular() in parent vite.config.js - all works properly. But when I want to use vitest for tests and also storybook, merging 2 angular plugins cause that error.

console.log() at vite final function can show that config come to vite final is parent vite.config.mts with "test" section

pumano avatar Dec 10 '24 20:12 pumano

@pumano what is the viteConfigPath set to in the main.ts for storybook?

brandonroberts avatar Dec 10 '24 21:12 brandonroberts

@brandonroberts

import type { StorybookConfig } from '@storybook/angular';
import type { StorybookConfigVite } from '@storybook/builder-vite';
import type { UserConfig } from 'vite';

const config: StorybookConfig & StorybookConfigVite = {
  stories: ['../**/*.stories.@(js|jsx|ts|tsx|mdx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-mdx-gfm', // mdx-gfm
    '@storybook/addon-a11y', // Catch accessibility issues
  ],
  framework: {
    name: '@storybook/angular',
    options: {},
  },
  /*
  typescript: {
    check: true, // type-check stories during Storybook build
  },
  */
  core: {
    disableTelemetry: true, // 👈 Disables telemetry
    builder: {
      name: '@storybook/builder-vite',
      options: {
        viteConfigPath: undefined,
      },
    },
  },
  staticDirs: ['../assets'],
  docs: {
    // set to change the name of generated docs entries
    defaultName: 'Docs',
  },
  async viteFinal(config: UserConfig) {
    // Merge custom configuration into the default config
    const { mergeConfig } = await import('vite');
    const { default: angular } = await import('@analogjs/vite-plugin-angular');

    return mergeConfig(config, {
      // Add dependencies to pre-optimization
      optimizeDeps: {
        include: [
          'react/jsx-dev-runtime',
          '@storybook/angular',
          '@storybook/angular/dist/client',
          '@angular/compiler',
          '@storybook/blocks',
          'tslib',
        ],
      },
      plugins: [angular({ jit: true, tsconfig: './.storybook/tsconfig.json' })],
    });
  },
};

export default config;

// To customize your webpack configuration you can use the webpackFinal field.
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
// and https://nx.dev/packages/storybook/documents/custom-builder-configs

note: storybook latest 8.4.7

pumano avatar Dec 10 '24 21:12 pumano

@brandonroberts I'm really sorry) but it fix partially. It's working now, but ruin tailwind styles. I really found workaround, but, what is very interested, if 2 configs merged (parent + vite final with angular plugin), it cost 2 times longer to start storybook due to double processing via plugins. They really not merged properly, I think it's bug or maybe not, but merge config add new items, not update previously added plugins.

Workaround: just rename vite.config.mts in nx library directory to vitest.config.mts it's really working with vitest, and NOT loaded by storybook (where plugins properly loaded and angular plugins under the hood load 1 time only).

Thank you @brandonroberts for your work! Hope some note to config collision is nice to have at analog website at guide to vitest section.

pumano avatar Dec 11 '24 17:12 pumano

@pumano no problem. 1.10.2-beta.6 contains a proper fix where multiple configurations with plugins don't cause issues with external templates and styles.

Tested with the reproduction instructions in the GitHub repo below

https://github.com/brandonroberts/issue-1288-nx

brandonroberts avatar Dec 11 '24 17:12 brandonroberts

Good idea with naming the separate files though in that case

brandonroberts avatar Dec 11 '24 17:12 brandonroberts

@brandonroberts OK I will try beta.6 now, later add results

pumano avatar Dec 11 '24 17:12 pumano

@brandonroberts beta.6 with no luck. I really debug that: in viteFinal storybook already load vite.config.mts with load angular plugin, nx-copy-assets-plugin (which really harm when try to build storybook, that plugin just copy *.md files not to dist folder but in nx lib folder)

only way to properly handle vitest + storybook in one nx lib now is not use vite.config.mts because viteConfigPath: undefined somehow not processed by storybook at all.

I'm already test it, vitest works good with vitest.config.mts and storybook works great with main.ts viteFinal config where angular plugin added

pumano avatar Dec 11 '24 17:12 pumano

@pumano are you getting the same error or just the slowdown?

brandonroberts avatar Dec 11 '24 17:12 brandonroberts

@brandonroberts i don't get error more, only slowdown and wrong tailwindcss processing. (I think that caused because plugins really duplicated.

I try to filter plugins, but they come to viteFinal as in promise. After trying it, I really understand, that trying to filtering something, is not good idea, because looks like monkey patching.

Final thoughts about it: I can solve problem: vitest+ storybook + vite its give me 2 mins less in pipeline time for building storybook. Thank you for being it possible.

pumano avatar Dec 11 '24 18:12 pumano

Great to hear. I'll consider the bug fixed, and we'll add some notes to the docs about usage of Storybook with Vitest and the configs

brandonroberts avatar Dec 11 '24 18:12 brandonroberts

@brandonroberts FYI similar issue at storybook: https://github.com/storybookjs/storybook/issues/29777

pumano avatar Dec 11 '24 19:12 pumano

It also says in their docs to point to a non-existent file if you don't want to load the main config, but that throws an error.

image

brandonroberts avatar Dec 11 '24 19:12 brandonroberts