tarling
tarling

Reputation: 1957

Using a full URL in a dynamic import()

Is it possible to use a full URL in a dynamic import() statement in ES6/Typescript?

import('https://foo.com/mymodule.js').then(() => {
    console.log('mymodule is loaded');
});

I get an error

//Cannot find module 'https://foo.com/mymodule.js'.

With Webpack and Typescript, we're already successfully using a relative path with a dynamic import

import(/* webpackChunkName: "mymodule" */ '../mymodule');

so it seems that Webpack already does module loading at runtime.

Upvotes: 33

Views: 35140

Answers (3)

Turbo
Turbo

Reputation: 688

Pure ES6 module without bundler

Most of the browsers now support ES6 modules natively. You need to define type="module" in the script tag.

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <script type="module">
        import camelCase from "http://localhost:40080/camelCase.js";
        import * as systemX from "https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.4/system.js";
        console.log(systemX);
        console.log(camelCase);
    </script>
</head>
<body>
    <h1>Hello</h1>
</body>
</html>

Alternatively, you can link to file as well.

<!-- move all previoous code to main.js -->
<script type="module" src="./main.js"></script>

Further reading:

https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/

Webpack

I tested the below trick and it works.

import(/* webpackIgnore: true */ 'http://example.com/some-module/some-module.bundle.js').then(module => console.log(module.default));

https://github.com/webpack/webpack/issues/8341#issuecomment-436550381

**Please note that CORS must be allowed from the webserver for both use cases.

Upvotes: 12

Ben Aston
Ben Aston

Reputation: 55779

ES2020 introduces a new function-like syntax for import, so-called "dynamic imports" permitting the dynamic import of JavaScript modules. The precise implementation of the importing process is left to the host (eg the browser, or Node.js), but modern web browsers do implement dynamic loading over HTTP using this syntax, with the module identified using a URL:

// foo.js at example.com
export function foo() {
    return 'this is foo'
}

// bar.js, running in the client
const { foo } = await import('http://example.com/my-module.js')
foo() // "this is foo"

Note that there are CORS and MIME-type constraints that you need to bear in mind. This and that are relevant.

Upvotes: 21

Estus Flask
Estus Flask

Reputation: 223268

ES modules aren't guaranteed to support URLs neither in static import nor in dynamic import(). Current browser versions (Chrome-based, Firefox, Safari) support URLs for both static and dynamic import, the implementation relies on CORS mechanism and may vary. Node.js supports this only with custom ESM loader, it's unlikely that it will allow this by default in future because of security concerns.

It may be possible to handle HTTP transport in Webpack via third-party plugin.

Script loading can be handled by SystemJS:

System.config({
  paths: {
    'mymodule': 'https://example.com/mymodule.js'
  }
});

System.import('mymodule')
.then(mymodule => {
  ...
})
.catch(error => console.error(error));

Or:

System.import('https://example.com/mymodule.js')
.then(mymodule => {
  ...
})
.catch(error => console.error(error));

SystemJS also provides capabilities to process loaded scripts when necessary, e.g. a way in which modules should be handled in these scripts.

Upvotes: 7

Related Questions