Aurelia、webpack 和图片的动态引用

Aurelia, webpack and dynamic reference to images

假设我们有这样的标记(我知道有多个 tbody)。

<tbody repeat.for="order of orders">
  <tr repeat.for="line of order.lines">
    <td>
      <img if.bind="order.urgent === 'T'" src="../app/alert.svg">
      <img if.bind="line.outOfSquare" src="../app/oos.svg">
    </td>
    <td class="min-width">
      <img src.bind="'../app/'+line.type+'.svg'" alt="${line.type}">
    </td>
  </tr>
</tbody>

dotnet new Aurelia 创建的默认项目中,图像作为 DataUrls 内联,因为它们很小。这是合理的,但根据绑定数据,它们在多行中重复出现。调整 webpack.config.js 将阈值降低到 1024 字节,我们有

{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=1024' }

现在图像在 wwwroot/dist 中显示为散列名称,并且 URL 被重写。计算出的 URL 目标也被添加到 webpack.config.js

  ,new GlobDependenciesPlugin({
    "boot": [
      "ClientApp/app/components/**/*.svg"
    ]
  })

不幸的是,计算的 URLs 没有被重写。

src.bind="'../app/'+line.type+'.svg'"

现在它们坏了。

如何在 运行 时解析应用程序相对路径?

我们需要在 运行 时解决这个问题,但到目前为止我找不到任何支持这样做的方法。已提出各种可能性:

我自己的研究表明,有 webpack 插件将这些映射作为 json,但我对 Aurelia 构建过程的浅薄理解不允许我利用这一点——除了我不知道的其他事情不知道如何使此输出可供应用程序使用。

这似乎是相关的,但无知阻碍了我。

我尝试使用 require 没有成功,但我怀疑自动在 Aurelia 模块范围内的 require 方法不是可能解析映射的 Webpack require。大概 webpack 在 运行 时间可以加载和解码打包的应用程序,但我真的不知道,因为到目前为止它只是工作,让我在幸福的无知中操作。

我知道我可以通过使用对资源的静态引用分别处理每个行类型来将其嵌入到页面中,如下所示:

<img if.bind="line.type === 'AL'" src="../app/al.svg">
<img if.bind="line.type === 'GD'" src="../app/gd.svg">

但这是高维护代码。

另一种可能是走另一条路。借用放置一个隐藏的 div 充满 imgs 的建议,如果这些都是内联的,那么可以通过绑定复制图像。

使用 require.context 你可以告诉 webpack 捆绑所有匹配特定模式的文件,然后使用创建的上下文在运行时动态解析它们的路径。

使用单一上下文和长路径解析所有图像

假设您有一个文件夹 src/assets/images,其中包含所有图像。其中一张图片名为 image-1.jpg。您可以像这样创建文件 src/images.js

const imageContext = require.context(
  ".",
  true,
  /^\.\/.*\.(jpe?g|png|gif)$/i
);
export { imageContext };

此上下文将(递归地)包含 src 下的所有图像。然后,例如 app.js,导入并使用它来解析您的图像:

import { imageContext } from "./images";

export class App {
    constructor() {
        this.img = imageContext("./assets/images/image-1.jpg"); 

        // resolved: '/src/assets/images/image-1.f1224ebcc42b44226aa414bce80fd715.jpg'
    }
}

<img src.bind="img">

解析特定文件夹中的图像,短路径

注意:您传递给上下文以解析图像的路径必须相对于您声明时传递给上下文的路径。因此,如果您有这样的 src/assets/images.js

const imageContext = require.context(
  "./images",
  true,
  /^\.\/.*\.(jpe?g|png|gif)$/i
);
export { imageContext };

然后在 src/app.js 你会这样做:

import { imageContext } from "./images";

export class App {
    constructor() {
        this.img = imageContext("./image-1.jpg"); 

        // resolved: '/src/assets/images/image-1.f1224ebcc42b44226aa414bce80fd715.jpg'
    }
}

加载具有特定模式的所有图像

如果您为要一起显示的每组图像创建一个上下文,它会变得更加容易:

src/pages/album/album.js:

const ctx = require.context(
  "../../assets/images",
  true,
  /^\.\/.*some-special-pattern.*\.(jpe?g|png|gif)$/i
);

export class Album {
    constructor() {
        this.images = ctx.keys().forEach(imageContext);
    }
}

<img repeat.for="img of images" src.bind="img">

让 Aurelia 施展魔法

创建一个 ValueConverter 例如:

src/resources/converters/image-context.js:

const imageContext = require.context(
  "../../",
  true,
  /^\.\/.*\.(jpe?g|png|gif)$/i
);

export class ImageContextValueConverter {
    toView(name) {
        const key = imageContext.keys().find(k => k.includes(name));
        return imageContext(key);
    }
}

src/resources/index.js

import { PLATFORM } from "aurelia-pal";

export function configure(config) {
    config.globalResources([
        PLATFORM.moduleName("resources/converters/image-context")
    ]);
}

然后在其他任何地方,例如获得 src/assets/images/image-1.jpg:

<img src.bind="'image-1' | imageContext">

Url-加载程序问题

当我尝试在我的项目中这样做时,我 运行 遇到了 url-loader 的问题,但我无法让它工作。感觉 url-loader 被最新的 webpack 版本破坏了,因为它也忽略了 limit 选项。我不得不完全抛弃 url-loader 来处理图像。我会更新我的答案 if/when 我让它工作。