如何配置 vite 以加载从 node_modules 导入的样式表中的相关图像?

How can vite be configured to load relative images in stylesheets imported from node_modules?

我有一个使用 UIkit 的应用程序,Less 用于本地样式,Vite 用于前端工具(捆绑等)。我不确定这是否相关,但这是我要升级到 Vue 3/Vite 的 Vue 2/Webpack 应用程序。

Per UIkit's Less documentation, we import UIkit's uikit.theme.less file in our project's base less file. UIkit's stylesheets have some relative paths to SVG files that get run through less's data-uri function(以下示例)。这在 Webpack 上工作得很好,但在 Vite 上就不太管用了。据我了解,对于小文件,data-uri 将对资产进行 UTF-8 编码并基本上内联它——至少这是我们在 Webpack 包中得到的。但是在我们的 Vite 构建中,这些相对图像路径似乎没有被解析,data-uri 因此退回到 url(),我们得到图像的 404s。

例如,在 UIkit 的代码中,相对 旋转图像的路径被定义为 here; it's used in a select.uk-select. And here that path is passed to a .svg-fill mixin (here)。当我们使用 Vite 或 运行 本地开发服务器捆绑代码时,结果是:

background-image: url(../../images/backgrounds/form-select.svg);

那当然不会加载,因为“图像”目录是相对于 form.less 文件的。在 Webpack 中,输出符合预期:

background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23001c30' d='M12 1 9 6h6zM12 13 9 8h6z'/%3E%3C/svg%3E");

对于这类问题,我通常会包含一个 HTML/CSS/JS 片段;但是,我认为 SO 不支持 Vite。因此,我包括了一个小的 Stackblitz,它最低限度地演示了这个问题:https://stackblitz.com/edit/vite-esqmqc?file=main.js 请参阅 main.jsstyle.less,并注意控制台中出现 404 错误,抱怨上述 form-select.svg 文件.

如果问题不清楚,如何让Vite解析与node_modules中的依赖相关的图像?

提前致谢。

解决方法是配置 resolve.alias to point ../../images to uikit/src/images (which resolves to the uikit package under node_modules/). This tells Vite how to resolve the problematic relative image paths

resolve.alias 配置作为 entries. Each entry can have a custom resolver 传递给 @rollup/plugin-alias,可用于仅替换来自 UIKit 的导入。但是,它要求 uikit.theme.less 的导入在其自己的文件中,以便自定义解析器可以正确识别导入程序,以确定何时替换导入。

  1. uikit.theme.less 的导入放在自己的文件中,然后从 main.js(而不是 style.less)导入:
// style.less
// @import './node_modules/uikit/src/less/uikit.theme.less'; ❌ move to own file
// my-uikit.less
@import './node_modules/uikit/src/less/uikit.theme.less';
// main.js
import './style.less';
import './my-uikit.less';
  1. 使用以下配置创建 vite.config.js
// vite.config.js
import { defineConfig } from 'vite';
import { fileURLToPath } from 'url';
import { basename } from 'path';

export default defineConfig({
  resolve: {
    alias: [
      {
        find: '../../images',
        replacement: '',
        customResolver(updatedId, importer, resolveOptions) {
          // don't replace if importer is not our my-uikit.less
          if (basename(importer) !== 'my-uikit.less') {
            return '../../images';
          }

          return fileURLToPath(
            new URL(
              './node_modules/uikit/src/images' + updatedId,
              import.meta.url
            )
          );
        },
      },
    ],
  },
})

demo