Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand how to package non-JavaScript static resources

2025-04-12 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "how to understand the packaging of non-JavaScript static resources", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to package non-JavaScript static resources.

Suppose you are developing a web application. In this case, you will probably have to deal with not only the JavaScript module, but also various other resources-Web Workers (it is also JavaScript, but it has a separate set of build dependent diagrams), images, CSS, fonts, WebAssembly modules, and so on.

One possible way to load static resources is to reference them directly in HTML, but usually they are logically coupled to other reusable components. For example, the CSS of a custom drop-down menu is associated with its JavaScript section, the icon image is related to the toolbar component, and the WebAssembly module is dependent on its JavaScript glue. In these cases, a more convenient and quick way is to reference resources directly from their JavaScript modules and load them dynamically when the corresponding components are loaded.

However, the build systems of most large projects make additional optimizations and reorganization of the content-such as packaging and minimization (minimize). The build system cannot execute the code and predict the result of execution, and there is no reason to traverse to determine whether every possible string in the JavaScript is a resource URL. So how can they "see" the dynamic resources loaded by JavaScript components and include them in the build artifact?

1. Custom import in the packaging tool

A common method is to take advantage of existing static import syntax. Some packaging tools may automatically detect formats through file extensions, while others allow plug-ins to use custom URL Scheme, such as the following example:

/ / ordinary JavaScript imports import {loadImg} from'. / utils.js';// special "URL import" static resources import imageUrl from 'asset-url:./image.png';import wasmUrl from' asset-url:./module.wasm';import workerUrl from 'js-url:./worker.js';loadImg (imageUrl); WebAssembly.instantiateStreaming (fetch (wasmUrl)); new Worker (workerUrl)

When a packaging tool plug-in finds an import with a recognized extension or URL Scheme (asset-url: and js-url: in the above example), it adds the referenced resource to the construction diagram, copies it to the final destination, performs the optimization for the resource type, and returns the final URL for use at run time.

The advantage of this approach is that the JavaScript import syntax is reused to ensure that all URL are static relative paths, which makes it easy for the build system to locate this dependency.

However, it has an obvious disadvantage: this code does not work directly in the browser because the browser does not know how to handle those custom import schemes or extensions. Of course, if you can control all the code and rely on packaging tools for development, that sounds good. However, to reduce hassle, it is becoming more and more common to use JavaScript modules directly in browsers (at least in the development process). A small demo may not need a packaging tool at all, even in production.

2. Import syntax commonly used in browsers and packaging tools

If you are developing a reusable component, you will want it to work in any environment, whether it is used directly in the browser or pre-built as part of a larger application. Most modern packaging tools accept the following JavaScript module import syntax:

New URL ('. / relative-path', import.meta.url)

It looks like a special syntax, but it is indeed a valid JavaScript expression that can be used directly in the browser or statically detected and processed by the packaging tool.

Using this syntax, the previous example can be rewritten as follows:

/ / regular JavaScript importimport {loadImg} from'. / utils.js';loadImg (new URL ('. / image.png', import.meta.url)); WebAssembly.instantiateStreaming (fetch (new URL ('. / module.wasm', import.meta.url)), {/ *... * /}); new Worker (new URL ('. / worker.js', import.meta.url))

Let's analyze how it works: new URL (...) The constructor parses the URL corresponding to the relative URL in the first parameter based on the absolute URL in the second parameter. In our example, the second parameter is import.meta.url [1], which is the URL of the current JavaScript module, so the first parameter can be any path relative to it.

Its advantages and disadvantages are similar to dynamic import. Although you can use import (...) Import content, such as import (someUrl), but packaging tools specifically handle imports with static URL import ('. / some-static-url.js'): use it as an import way to preprocess known dependencies at compile time, chunking the code and loading it dynamically.

Similarly, you can use new URL (...), such as new URL (relativeUrl, customAbsoluteBase), while the new URL ('..., import.meta.url) syntax explicitly tells the packaging tool to preprocess the dependency and package it with the main JavaScript resource.

3. Ambiguous relative URL

You might wonder why packaging tools can't detect other common grammars-for example, fetch ('. / module.wasm') without new URL wrappers.

The reason is that, unlike the import keyword, any dynamic request is parsed relative to the document itself, not to the current JavaScript file. For example, we have the following structure:

Index.html:

Src/main.jsmodule.wasm

If you want to load module.wasm from main.js, your first reaction may be to use a relative path reference such as fetch ('. / module.wasm').

However, fetch does not know the URL of the JavaScript file it executes; instead, it parses the URL relative to the document. As a result, fetch ('. / module.wasm') will eventually try to load http://example.com/module.wasm instead of the expected http://example.com/src/module.wasm, resulting in failure (or, in worse luck, silently loading a resource that is different from what you expected).

By wrapping the relative URL as new URL ('...', import.meta.url), you can avoid this problem and ensure that any provided URL is parsed relative to the URL (import.meta.url) of the current JavaScript module before it is passed to any loader.

As long as you use fetch (new URL ('. / module.wasm', import.meta.url)) instead of fetch ('. / module.wasm'), you can successfully load the expected WebAssembly module and give the packaging tool a reliable way to find these relative paths at build time.

4. Support in the tool chain 4.1 Packaging tool

The following packaging tools already support new URL syntax:

Webpack v5

Rollup (generic resources are supported through plug-in support: @ web/rollup-plugin-import-meta-assets, while @ surma/rollup-plugin-off-main-thread supports Workers.)

Parcel v2 (beta) (translator's note: at the time of this translation, Parcel V2 has been officially released: https://parceljs.org/blog/v2)

Vite

5 、 WebAssembly

When using WebAssembly, you usually do not manually load the Wasm module, but import the JavaScript glue code issued by the tool chain. The following tool chain can generate new URL (...) for you. Syntax:

5.1 Candlestick compiled with Emscripten +

When using the Emscripten toolchain, we can ask it to output ES6 module glue code instead of normal JS code with the following options:

$emcc input.cpp-o output.mjs## if you don't want to use the mjs extension: $emcc input.cpp-o output.js-s EXPORT_ES6

When using this option, the glue code output will use the new URL (..., import.meta.url) syntax, so that the packaging tool can automatically find the relevant Wasm file.

This syntax can also support compilation of WebAssembly threads by adding the-pthread parameter.

$emcc input.cpp-o output.mjs-pthread## if you don't want to use the mjs extension: $emcc input.cpp-o output.js-s EXPORT_ES6-pthread

In this case, the generated Web Worker will be referenced in the same way and will also be correctly loaded by the packaging tool and browser.

5.2 Rust compiled with wasm-pack / wasm-bindgen

Wasm-pack, WebAssembly's main Rust tool chain, also has several output modes.

By default, it will output a JavaScript module that depends on the WebAssembly ESM integration proposal. At the time of this writing, this proposal is still experimental, and the output will be valid only if you use Webpack packaging.

Alternatively, we can ask wasm-pack through the-target web parameter to output a browser-compatible ES6 module:

$wasm-pack build-target web

The output will use the new URL (..., import.meta.url) syntax mentioned earlier, and the Wasm file will be automatically discovered by the packaging tool.

If you want to use WebAssembly threads through Rust, this is a bit complicated. Please see the appropriate section of the guide [13] to learn more.

In short, you can't use any thread API, but if you use Rayon [14], you can try the wasm-bingen-rayon [15] adapter so that it can generate Worker that can run on Web. The JavaScript glue used by wasm-bindgen-rayon also includes [16] new URL (...) Syntax, so Workers can also be discovered and introduced by packaging tools.

6. Future import methods 6.1 import.meta.resolve

One potential future improvement is the specialized import.meta.resolve (...) Grammar. It will allow content relative to the current module to be parsed in a more direct way without the need for additional parameters.

/ / current syntax new URL ('...', import.meta.url) / / future syntax await import.meta.resolve ('...')

It also integrates better with import dependency graphs (import maps) and custom parsers because it is handled through the same modular parsing system as import syntax. This is also a more reliable signal for packaging tools because it is a static syntax that does not rely on runtime API such as URL.

Import.meta.resolve has been implemented in Node.js as an experimental feature, but there are still some questions about how it should work on Web.

6.2 Import assertions

Import assertions (import assertions) is a new feature that allows you to import types other than ECMAScript modules, but now only JSON types are supported.

Foo.json

{"answer": 42}

Main.mjs

Import json from'. / foo.json' assert {type: 'json'}; console.log (json.answer); / / 42

(translator's note: it's also interesting about this less intuitive grammatical choice, https://github.com/tc39/proposal-import-assertions/issues/12)

They may also be used by packaging tools and replace scenarios currently supported by new URL syntax, but the types in import assertions need to be supported one by one, and only JSON,CSS modules are currently supported, but other types of resource imports still require a more generic solution.

For more information about this feature, see the functional explanation on v8.dev [19].

7. Summary

As you can see, there are various ways to include non-JavaScript resources on the network, but they have their own advantages and disadvantages and cannot work in all tool chains at the same time. Some future proposals may allow us to import these resources with special syntax, but we haven't come this far yet.

Until that day, the new URL (..., import.meta.url) syntax is the most promising solution, and today it works in browsers, various bundles, and WebAssembly toolchains.

At this point, I believe you have a deeper understanding of "how to package non-JavaScript static resources". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report