Using Webpack Asset Modules

Webpack 5 provides a couple of techniques for importing assets such as images. These include:

  • Using import
  • Using new URL()

USING IMPORT

We need to generate code such as:

import logo from "./logo.png";

We can achieve this using:

@module("./logo.png")
external logo: string = "default"

Which generates:

import LogoPng from "./logo.png";

USING NEW URL()

We need to generate code such as:

const logo = new URL('./logo.png', import.meta.url);

Here’s what I’ve come up with for this:

// Create an external to allow us to use `import.meta.url`
type webpackMeta = {url: string}
type webpackImport = {meta: webpackMeta}
@val external webpackImport: webpackImport = "import"

// Function that compiles to `new URL()`
type url = {href: string, pathname: string}
@new external localFileUrl: (string, string) => url = "URL"

And I can now use this as follows:

let logo = localFileUrl("./logo.png", webpackImport.meta.url)

Which compiles to:

var logo = new URL("./logo.png", import.meta.url);

CAN THIS BE SIMPLER?

I was wondering if there might be a simpler way to achieve either of these outcomes?

As I understand it, one important constraint is that the generated code must include the file path literally, which is parsed by Webpack:

/* import with literal file path */
import logo from "./logo.png";

/* new URL() with literal file path */
const logo = new URL('./logo.png', import.meta.url);

If the generated code includes variable names (such as a function argument) I’m not sure if it will work.

Thanks

I’m not sure you can do any better than this:

This is already fairly similar to an import, not more complex in my opinion, and syntax-wise this might be improved in the future with new binding syntaxes.

For new URL, you can make things a bit better by using scope for import.meta.url:

@scope(("import","meta")) @val external importMetaUrl: string = "url"

You could in theory do this:

type url
@new external localFileUrl: (string, string) => url = "URL"
let localFileUrl = path => localFileUrl(path, importMetaUrl)

But as you said, webpack might not process it as expected, but it might be worth making some experiments.

1 Like

Hi @tsnobip

The @scope tip is great.

I tried converting localFileUrl to a function, and it actually worked because ReScript optimised the function call away. Amazing.

Thanks for your tips.