Aurelia、webpack 和对图像的动态引用

Posted

技术标签:

【中文标题】Aurelia、webpack 和对图像的动态引用【英文标题】:Aurelia, webpack and dynamic reference to images 【发布时间】:2018-10-04 01:42:20 【问题描述】:

假设我们有这样的标记(多个 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'" >
    </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"
    ]
  )

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

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

他们现在坏了。

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

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

完全禁止处理图像并使用构建任务来打包它们 在运行时使用 require 来转换 URL 使用一个隐藏的 div,其中充满了带有静态 URL 的 img 和原始 URL 作为 id 值,然后使用这些在运行时进行映射。

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

这似乎是相关的,但无知阻碍了我。 How to load image files with webpack file-loader

我尝试使用 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">

但这是高维护代码。

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

【问题讨论】:

CopyWebpackPlugin 不是一个选项吗?只是让它物理地将文件复制到 dist 文件夹吗? 【参考方案1】:

使用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'
    

&lt;img src.bind="img"&gt;

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

注意:您传递给上下文以解析图像的路径必须相对于您在声明时传递给上下文的路径。所以如果你有这样的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);
    

&lt;img repeat.for="img of images" src.bind="img"&gt;

让 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:

&lt;img src.bind="'image-1' | imageContext">

网址加载器问题

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

【讨论】:

这正是我寻求的信息。您显然了解我面临的问题以及提出问题的动机,并且您的回答足够完整,可以为进一步调查和自学提供框架。太棒了! .find(k =&gt; k.contains(name)) 中您的意思是.find(k =&gt; k.includes(name)) 还是.find(k =&gt; k.startsWith(name))? Contains 是一个 Array 方法。 我的意思是.contains()。它也是一个字符串方法——字符串有许多与数组相同的方法。最终这只是一个简单的示例,但您也可以传递函数名称以获得更大的灵活性。例如正则表达式匹配toView(arg, method) 然后.find(k =&gt; k[method](arg)),用法:/\d+/ | | imageContext:'match' 查找名称中带有数字的所有图像。 我是这么认为的,但是代码无法在 Edge 上编译或运行,然后又在 Firefox 上运行。因为你的回答让我感到惊讶,所以我查了两个名字,有一个复杂的故事,以 contains 结尾,不推荐使用 includes.developer.mozilla.org/en-US/docs/Web/javascript/Reference/… 我会被诅咒的,永远不知道.. 花了 99% 的时间在 chrome 上。然后我会将我的答案更新为includes。谢谢你告诉我!

以上是关于Aurelia、webpack 和对图像的动态引用的主要内容,如果未能解决你的问题,请参考以下文章

Aurelia 使用模板字符串动态绑定变量

动态添加图像 React Webpack

Aurelia:无法将控制器链接到我的导航栏模板

webpack引用动态资源路径错误的解决方案

webpack css-loader 在外部样式表的 url() 引用中找不到图像

javascript 使用webpack动态导入和使用图像并做出反应