originjs / vite-plugins

Other
171 stars 30 forks source link

vite-plugin-require-context doesn't work for images #32

Open ScubaDaniel opened 2 years ago

ScubaDaniel commented 2 years ago

I've tried both of the following with various levels of configuration and can't get it to work.

I've defined the projectBasePath to the root directory just above src and as src and neither work. I've tried defining the asset in assetsInclude and build.rollupOptions.external and nothing seems to change. Is this plugin for JS only?

// src/SISU/shared/utilities/images-helper.ts
export const images = require.context("@Product/images/", false, /^.+?\.png|jpg|svg|gif$/);
// src/SISU/shared/utilities/images-helper.ts
export const images = require.context("../../../Product/images/", false, /^.+?\.png|jpg|svg|gif$/);

Output:

[vite]: Rollup failed to resolve import "/src/Product/images/arrow_left.png" from "utilities/images-helper.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`

Error: [vite]: Rollup failed to resolve import "/src/Product/images/arrow_left.png" from "utilities/images-helper.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`

    at onRollupWarning (E:\root\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41489:19)
    at onwarn (E:\root\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41305:13)
    at Object.onwarn (E:\root\node_modules\rollup\dist\shared\rollup.js:23226:13)
    at ModuleLoader.handleResolveId (E:\root\node_modules\rollup\dist\shared\rollup.js:22510:26)
    at E:\root\node_modules\rollup\dist\shared\rollup.js:22471:26

TypeError: Cannot read properties of undefined (reading 'httpServer')
PeterAlfredLee commented 2 years ago

Hi @ScubaDaniel Thank you for your reporting.

This require.context plugin just transform the require.contextsyntax into import, not containing any loaders. Actually vite has integrated asset loader that can handle images - this loader will return the url of the image.

What are you expecting to get when you are importing an image? By default, vite will return the url of the image.

I made some tests with require.context and images, and they worked well. Maybe you can provide some more details?

// test.js
export const images = require.context('../assets', false, /^.+?\.png|jpg|svg|gif$/);
// HelloWorld.vue
<script setup>
import image from '../assets/logo.png'
import * as test from './test'
const images = require.context('../assets', false, /^.+?\.png|jpg|svg|gif$/)
import {onMounted, ref} from 'vue'

defineProps({
  msg: String
})

const count = ref(0)

onMounted(() => {
  console.log(test);
  console.log(image);
  console.log(images);
})
</script>
ScubaDaniel commented 2 years ago

Thanks for the quick response, @PeterAlfredLee!

Yes, the URL is all I want in this scenario. I was able to get the glob import working yesterday, but that is going to require I split code between production using webpack syntax versus integration testing using this glob import. I'd love to use this plugin if it works like you're saying!

I tried removing the trailing slash from my calls like you provided, but unfortunately that returns the same error. Are there any details I can provide that would be helpful to troubleshoot this? We're running Vite through Playwright, if that matters.

I'm wondering if it's related to relative paths and where I'm running tests from... I was previously running from root/src/SISU/shared (a workspace in our repo) and got a bit more information when I ran it from root:

E:\root> yarn run test-ct --headed --config=src\SISU\shared\playwright-ct.config.ts

   at node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41489

  41487 |         // throw unless it's commonjs external...
  41488 |         if (!importer || !/\?commonjs-external$/.test(importer)) {
> 41489 |             throw new Error(`[vite]: Rollup failed to resolve import "${id}" from "${importer}".\n` +
        |                   ^
  41490 |                 `This is most likely unintended because it can break your application at runtime.\n` +
  41491 |                 `If you do want to externalize this module explicitly add it to\n` +
  41492 |                 `\`build.rollupOptions.external\``);

    at onRollupWarning (E:\root\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41489:19)
    at onwarn (E:\root\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41305:13)
    at Object.onwarn (E:\root\node_modules\rollup\dist\shared\rollup.js:23226:13)
    at ModuleLoader.handleResolveId (E:\root\node_modules\rollup\dist\shared\rollup.js:22510:26)
    at E:\root\node_modules\rollup\dist\shared\rollup.js:22471:26

TypeError: Cannot read properties of undefined (reading 'httpServer')

Directory structure:

I'm following this guide for testing components and my playwright-wt.config.ts looks like the following:

import type { PlaywrightTestConfig } from "@playwright/experimental-ct-react";
import { devices } from "@playwright/experimental-ct-react";
import ViteRequireContext from "@originjs/vite-plugin-require-context";

/**
 * See https://playwright.dev/docs/test-configuration.
 */
const config: PlaywrightTestConfig = {
  testDir: "E:\\root",
  testMatch: /__integration__\/.*(test|spec)\.(js|ts|mjs|tsx)/,
  /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
  snapshotDir: "./__snapshots__",
  /* Maximum time one test can run for. */
  timeout: 1000000 * 1000,
  /* Run tests in files in parallel */
  fullyParallel: true,
  /* Fail the build on CI if you accidentally left test.only in the source code. */
  forbidOnly: !!process.env.CI,
  /* Retry on CI only */
  retries: process.env.CI ? 2 : 0,
  /* Opt out of parallel tests on CI. */
  workers: process.env.CI ? 1 : undefined,
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
  reporter: "html",
  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
  use: {
    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
    trace: "on-first-retry",

    /* Port to use for Playwright component endpoint. */
    ctPort: 3100,
    ctViteConfig: {
      plugins: [
        ViteRequireContext({
          //  projectBasePath: "E:\\root",
        }),
      ],
    },
  },

  /* Configure projects for major browsers */
  projects: [
    {
      name: "chromium",
      use: {
        ...devices["Desktop Chrome"],
      },
    },
    {
      name: "firefox",
      use: {
        ...devices["Desktop Firefox"],
      },
    },
    {
      name: "webkit",
      use: {
        ...devices["Desktop Safari"],
      },
    },
  ],
};

export default config;
ScubaDaniel commented 2 years ago

I just read some documentation on Vite plugins. Should this be run before the Vite core plugins? I noticed I am getting a different error when using the following config:

plugins: [
  {
    ...ViteRequireContext(),
    enforce: "pre",
  },
]

Error:

[vite:require-context] Cannot read properties of undefined (reading '0')
file: E:/root/src/SISU/shared/utilities/images-helper.ts

TypeError: Cannot read properties of undefined (reading '0')

    at transformRequireContext (E:\root\node_modules\@originjs\vite-plugin-require-context\lib\index.js:106:22)
    at E:\root\node_modules\@originjs\vite-plugin-require-context\lib\index.js:58:114
    at Array.forEach (<anonymous>)
    at Object.transform (E:root\node_modules\@originjs\vite-plugin-require-context\lib\index.js:52:35)
    at E:\root\node_modules\rollup\dist\shared\rollup.js:22870:37

TypeError: Cannot read properties of undefined (reading 'httpServer')
PeterAlfredLee commented 2 years ago

I don't think the configure option enforce: "pre" would help - this option only make the require.context plugin transforms before vite's default plugin do.

[vite]: Rollup failed to resolve import "/src/Product/images/arrow_left.png" from "utilities/images-helper.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`

Error: [vite]: Rollup failed to resolve import "/src/Product/images/arrow_left.png" from "utilities/images-helper.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`

    at onRollupWarning (E:\root\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41489:19)
    at onwarn (E:\root\node_modules\vite\dist\node\chunks\dep-59dc6e00.js:41305:13)
    at Object.onwarn (E:\root\node_modules\rollup\dist\shared\rollup.js:23226:13)
    at ModuleLoader.handleResolveId (E:\root\node_modules\rollup\dist\shared\rollup.js:22510:26)
    at E:\root\node_modules\rollup\dist\shared\rollup.js:22471:26

TypeError: Cannot read properties of undefined (reading 'httpServer')

Through your original output, seems the plugin has already transformed the require.context("../../../Product/images/", false, /^.+?\.png|jpg|svg|gif$/) into urls of images /src/Product/images/arrow_left.png.

The error is weird - it reports that rollup cannot resolve the url as an import. It seems you only exported the require.context, and you didn't import anything. Could you provide some more detailed code on how are you using the exported images(I'm talking about the exported object export const images = require.context("@Product/images/", false, /^.+?\.png|jpg|svg|gif$/))?

ScubaDaniel commented 2 years ago

So my understanding is that require.context should return a method that allows you to "require" files inside that context, not just a list of files, correct?

Here is an example of consumption:

import { getFullImageName, images } from "../utilities/images-helper";

const Logo: React.FC<LogoProps> = function Logo() {
  return <img src={images(getFullImageName("some_image"))} />;
};
// images-helper.js
export const images = require.context("../../../Product/images", false, /^.+?\.png|jpg|svg|gif$/);

export function getFullImageName(imageName: string, extension: string = ""): string {
  const ext = extension || (isSvgSupported ? "svg" : "png");
  return `./${imageName}.${ext}`;
}

This seems to work with webpack without issue

PeterAlfredLee commented 2 years ago
import { getFullImageName, images } from "../utilities/images-helper";

const Logo: React.FC<LogoProps> = function Logo() {
  return <img src={images(getFullImageName("some_image"))} />;
};

I see. You are using require.context in jsx syntax. Seems we can't support such scenarios. Could you try it like this?

import { getFullImageName, images } from "../utilities/images-helper";

const imageSrc = images(getFullImageName("some_image"));
const Logo: React.FC<LogoProps> = function Logo() {
  return <img src={imageSrc} />;
};