Jadyn  Waelchi

Jadyn Waelchi

1626542400

Vitejs Your Frontend with Es Modules

Vitejs your frontend with es modules. Vitejs is a new builder for frontend applications, still in beta. We will look into vitejs by creating a react and a vuejs application and see how it will look like in the browser.
Vitejs is using es modules of these frontend frameworks, you see that es modules will be very important now and in the future. Deno is also making advantages out of es modules.

https://github.com/vitejs/vite

#vitejs #react #vuejs

What is GEEK

Buddha Community

Vitejs Your Frontend with Es Modules

Hire Frontend Developers

Create a new web app or revamp your existing website?

Every existing website or a web application that we see with an interactive and user-friendly interface are from Front-End developers who ensure that all visual effects come into existence. Hence, to build a visually appealing web app front-end development is required.

At HourlyDeveloper.io, you can Hire FrontEnd Developers as we have been actively working on new frontend development as well as frontend re-engineering projects from older technologies to newer.

Consult with experts: https://bit.ly/2YLhmFZ

#hire frontend developers #frontend developers #frontend development company #frontend development services #frontend development #frontend

Jadyn  Waelchi

Jadyn Waelchi

1626542400

Vitejs Your Frontend with Es Modules

Vitejs your frontend with es modules. Vitejs is a new builder for frontend applications, still in beta. We will look into vitejs by creating a react and a vuejs application and see how it will look like in the browser.
Vitejs is using es modules of these frontend frameworks, you see that es modules will be very important now and in the future. Deno is also making advantages out of es modules.

https://github.com/vitejs/vite

#vitejs #react #vuejs

Ray  Patel

Ray Patel

1619571780

Top 20 Most Useful Python Modules or Packages

 March 25, 2021  Deepak@321  0 Comments

Welcome to my blog, In this article, we will learn the top 20 most useful python modules or packages and these modules every Python developer should know.

Hello everybody and welcome back so in this article I’m going to be sharing with you 20 Python modules you need to know. Now I’ve split these python modules into four different categories to make little bit easier for us and the categories are:

  1. Web Development
  2. Data Science
  3. Machine Learning
  4. AI and graphical user interfaces.

Near the end of the article, I also share my personal favorite Python module so make sure you stay tuned to see what that is also make sure to share with me in the comments down below your favorite Python module.

#python #packages or libraries #python 20 modules #python 20 most usefull modules #python intersting modules #top 20 python libraries #top 20 python modules #top 20 python packages

Ahebwe  Oscar

Ahebwe Oscar

1623148379

Django + Vue3 — The Best of Both Frontends

In the previous articles of this series, I’ve demonstrated a method of integrating Django templates and Vue in such a way that preserves the strengths of both frontend frameworks.

Since those articles were published, Vue3 has been released, bringing a variety of improvements and a list of breaking changes. With these numerous changes, the code examples from the prior articles in this series no longer work directly with Vue3. But happily, with only a few isolated changes, the same general approach works well with Vue3 and, moreover, the code becomes, in my opinion, simpler. In fact, we need not alter our components, our Vuex stores, or even our vue.config.js to work with Vue3. Rather, the required changes are limited to the app initialization logic.

Instead of rehashing the ideas and approach described in prior articles of this series, this article will instead enumerate the changes needed to adapt the Vue2 solution to Vue3. At the same time, I’ll introduce a couple of additional changes that, while not strictly necessary for Vue3, improve the overall quality of the Vue + Django integration.

If you’re just starting with Vue + Django, I suggest reading from the start of these articles to learn more about the general approach utilized in this article. Or, to start hacking immediately, check out the sample application source code.

Overview of changes

In Vue2, app initialization was generally done with new Vue() constructor. However, this approach was eliminated in Vue3, so instead we will adapt the code to use the new createApp() method. Similarly, we no longer can instantiate the Vuex store with new Vuex.store() but will instead use createStore().

Both these changes are straightforward adaptations based on the Vue migration guide.

However, our usage with Django necessitates a couple additional changes. First, we must provide for passing of properties from Django template, as our previous approach, which relied on new Vue(), no longer works. Second, as we may potentially be adding several Vue apps to a single page, it behooves us to extract our app/store creation logic into a callable function.

#vuejs #django #django + vue3 — the best of both frontends #both frontend #vue3 #best of both frontends

Reid  Rohan

Reid Rohan

1658261760

ES-module-shims: Shims for New ES Modules Features on top

ES Module Shims

Shims modern ES Modules features like import maps on top of the baseline modules support in browsers supported by 95% of users.

When running in polyfill mode, the 67% of users with import maps entirely bypass the shim code entirely.

For the remaining 30% of users, the highly performant (see benchmarks) production and CSP-compatible shim kicks in to rewrite module specifiers driven by the Web Assembly ES Module Lexer.

The following modules features are polyfilled:

When running in shim mode, module rewriting is applied for all users and custom resolve and fetch hooks can be implemented allowing for custom resolution and streaming in-browser transform workflows.

Because we are still using the native module loader the edge cases work out comprehensively, including:

  • Live bindings in ES modules
  • Dynamic import expressions (import('src/' + varname'))
  • Circular references, with the execption that live bindings are disabled for the first unexecuted circular parent.

Built with Chomp

Usage

Include ES Module Shims with a async attribute on the script, then include an import map and module scripts normally:

<script async src="https://ga.jspm.io/npm:es-module-shims@1.5.9/dist/es-module-shims.js"></script>

<!-- https://generator.jspm.io/#U2NhYGBkDM0rySzJSU1hKEpNTC5xMLTQM9Az0C1K1jMAAKFS5w0gAA -->
<script type="importmap">
{
  "imports": {
    "react": "https://ga.jspm.io/npm:react@18.0.0-rc.0/index.js"
  },
  "scopes": {
    "https://ga.jspm.io/npm:react@18.0.0-rc.0/": {
      "object-assign": "https://ga.jspm.io/npm:object-assign@4.1.1/index.js"
    }
  }
}
</script>

<script type="module">
  import react from 'react';
  console.log(react);
</script>

In browsers without import maps support, a console error will be given:

Uncaught TypeError: Failed to resolve module specifier "app". Relative references must start with either "/", "./", or "../".
  at <anonymous>:1:15

This execution failure is a feature - it avoids the polyfill causing double execution. The first import being a bare specifier in the pattern above is important to ensure this.

This is because the polyfill cannot disable the native loader - instead it will only execute modules that would otherwise fail resolving or parsing to avoid duplicate fetches or executions that would cause performance and reliability issues.

Shim Mode

Shim mode is an alternative to polyfill mode and doesn't rely on native modules erroring - instead it is triggered by the existence of any <script type="importmap-shim"> or <script type="module-shim">, or when explicitly setting the shimMode init option.

In shim mode, only the above importmap-shim and module-shim tags will be parsed and executed by ES Module Shims.

Shim mode also provides some additional features that aren't yet natively supported such as supporting multiple import maps, external import maps with a "src" attribute, dynamically injecting import maps, and reading current import map state, which can be useful in certain applications.

Polyfill Mode Details

In polyfill mode, feature detections are performed for ES modules features. In browsers with full feature support no further processing is done.

In browsers with variable feature support, sources are analyzed with module specifiers rewritten using the very fast Wasm / asm.js lexer while sharing the source network fetch cache with the native loader.

Polyfill Features

The current default native baseline for the ES module shims polyfill mode is browsers supporting import maps.

If using more modern features like CSS Modules or JSON Modules, these need to be manually enabled via the polyfillEnable init option to raise the native baseline to only browsers supporting these features:

<script>
window.esmsInitOptions = { polyfillEnable: ['css-modules', 'json-modules'] }
</script>

To verify when the polyfill is actively engaging as opposed to relying on the native loader, a polyfill hook is also provided.

Polyfill Edge Case: Dynamic Import

The guarantee of the polyfill is that any module graph that would have failed will be reexecuted through the shim layer. This leaves any edge case where execution succeeds but not as expected. For example when using dynamic imports:

<script type="module">
  console.log('Executing');
  const dynamic = 'bare-specifier';
  import(dynamic).then(x => {
    console.log('Ok');
  }, err => {
    console.log('Fail');
  });
</script>

The native browser loader without import maps support will execute the above module fine, but fail on the lazy dynamic import.

ES Module Shims will not reexecute the above in browsers without import maps support though because it will see that the execution did complete successfully therefore it will not attempt reexecution and as a result, "Ok" is never logged.

Other examples include dynamically injecting import maps, or using import maps with a "src" attribute, which aren't supported in native Chrome.

This is why it is advisable to always ensure modules use syntax that will fail early to avoid non-execution.

If a static failure is not possible and dynamic import must be used, rather use the importShim ES Module Shims top-level loader:

<script type="module">
  console.log('Executing');
  const dynamic = 'bare-specifier';
  importShim(dynamic).then(x => {
    console.log('Ok');
  }, err => {
    console.log('Fail');
  });
</script>

importShim will automatically pass-through to native dynamic import or polyfill as necessary, just like it does for script tags.

Polyfill Edge Case: Instance Sharing

When running in polyfill mode, it can be thought of that are effectively two loaders running on the page - the ES Module Shims polyfill loader, and the native loader.

Note that instances are not shared between these loaders for consistency and performance.

As a result, if you have two module graphs - one native and one polyfilled, they will not share the same dependency instance, for example:

<script type="importmap">
{
  "imports": {
    "dep": "/dep.js"
  }
}
</script>
<script type="module">
import '/dep.js';
</script>
<script type="module">
import 'dep';
</script>

In the above, on browsers without import maps support, the /dep.js instance will be loaded natively by the first module, then the second import will fail.

ES Module Shims will pick up on the second import and reexecute /dep.js. As a result, /dep.js will be executed twice on the page.

For this reason it is important to always ensure all modules hit the polyfill path, either by having all graphs use import maps at the top-level, or via importShim directly.

Skip Polyfill

Adding the "noshim" attribute to the script tag will also ensure that ES Module Shims skips processing this script entirely:

<script type="module" noshim>
  // ...
</script>

Benchmarks

ES Module Shims is designed for production performance. A comprehensive benchmark suite tracks multiple loading scenarios for the project.

Benchmark summary:

  • ES Module Shims Chrome Passthrough (for 70% of users) results in ~5ms extra initialization time over native for ES Module Shims fetching, execution and initialization, and on a slow connection the additional non-blocking bandwidth cost of its 10KB compressed download as expected.
  • ES Module Shims Polyfilling (for the remaining 30% of users) is on average 1.4x - 1.5x slower than native module loading, and up to 1.8x slower on slow networks (most likely due to the browser preloader), both for cached and uncached loads, and this result scales linearly up to 10MB and 20k modules loaded executing on the fastest connection in just over 2 seconds in Firefox.
  • Very large import maps (100s of entries) cost only a few extra milliseconds upfront for the additional loading cost.

Features

Browser Support

Works in all browsers with baseline ES module support.

Browser Compatibility with ES Module Shims:

ES Modules FeaturesChrome (61+)Firefox (60+)Safari (10.1+)Edge (17+)
Executes Modules in Correct Order:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:1
Dynamic Import:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
import.meta.url:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
Module Workers:heavy_check_mark: ~68+:x:2:x:2:x:2
modulepreload:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
Import Maps:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
JSON Modules:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
CSS Modules:heavy_check_mark:3:heavy_check_mark:3:heavy_check_mark:3:heavy_check_mark:3
import.meta.resolve:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
Top-Level Await:heavy_check_mark: 89+:heavy_check_mark: 89+:x:4:x:4
  • 1: The Edge parallel execution ordering bug is corrected by ES Module Shims with an execution chain inlining approach.
  • 2: Module worker support cannot be implemented without dynamic import support in web workers.
  • 3: CSS module support requires a separate Constructable Stylesheets polyfill.
  • 4: Top-level await support is possible for ES Module Shims to implement, with the feature request tracking in https://github.com/guybedford/es-module-shims/issues/5.

Browser compatibility without ES module shims:

ES Modules FeaturesChrome (61+)Firefox (60+)Safari (10.1+)Edge (17+)
Executes Modules in Correct Order:heavy_check_mark::heavy_check_mark::heavy_check_mark::x:1
Dynamic Import:heavy_check_mark: 63+:heavy_check_mark: 67+:heavy_check_mark: 11.1+:x:
import.meta.url:heavy_check_mark: ~76+:heavy_check_mark: ~67+:heavy_check_mark: ~12+ ❕1:x:
Module Workers:heavy_check_mark: ~68+:x::x::x:
modulepreload:heavy_check_mark: 66+:x::x::x:
Import Maps:heavy_check_mark: 89+:x::x::x:
JSON Modules:heavy_check_mark: 91+:x::x::x:
CSS Modules:heavy_check_mark: 95+:x::x::x:
import.meta.resolve:x::x::x::x:
Top-Level Await:heavy_check_mark: 89+:heavy_check_mark: 89+:x::x:
  • 1: Edge executes parallel dependencies in non-deterministic order. (ChakraCore bug).
  • ~: Indicates the exact first version support has not yet been determined (PR's welcome!).
  • ❕1: On module redirects, Safari returns the request URL in import.meta.url instead of the response URL as per the spec.

Import Maps

Stability: WhatWG Standard, Single Browser Implementer

Import maps allow for importing "bare specifiers" in JavaScript modules, which prior to import maps throw in all browsers with native modules support.

Using this polyfill we can write:

<script type="importmap-shim">
{
  "imports": {
    "test": "/test.js"
  },
  "scopes": {
    "/": {
      "test-dep": "/test-dep.js"
    }
  }
}
</script>
<script type="module-shim">
  import test from "test";
  console.log(test);
</script>

All modules are still loaded with the native browser module loader, but with their specifiers rewritten then executed as Blob URLs, so there is a relatively minimal overhead to using a polyfill approach like this.

Multiple Import Maps

Multiple import maps are not currently supported in any native implementation, Chromium support is currently being tracked in https://bugs.chromium.org/p/chromium/issues/detail?id=927119.

In polyfill mode, multiple import maps are therefore not supported.

In shim mode, support for multiple importmap-shim scripts follows the import map extensions proposal.

External Import Maps

External import maps (using a "src" attribute) are not currently supported in any native implementation.

In polyfill mode, external import maps are therefore not supported.

In shim mode, external import maps are fully supported.

Dynamic Import Maps

Support for dynamically injecting import maps with JavaScript via eg:

document.body.appendChild(Object.assign(document.createElement('script'), {
  type: 'importmap',
  innerHTML: JSON.stringify({ imports: { x: './y.js' } }),
}));

is supported in Chromium, provided it is injected before any module loads and there is no other import map yet loaded (multiple import maps are not supported).

Both modes in ES Module Shims support dynamic injection using DOM Mutation Observers.

While in polyfill mode the same restrictions apply that multiple import maps, import maps with a src attribute, and import maps loaded after the first module load are not supported, in shim mode all of these behaviours are fully enabled for "importmap-shim".

Reading current import map state

To make it easy to keep track of import map state, es-module-shims provides a importShim.getImportMap utility function, available only in shim mode.

const importMap = importShim.getImportMap();

// importMap will be an object in the same shape as the json in a importmap script

Setting current import map state

To make it easy to set the import map state, es-module-shims provides a importShim.addImportMap utility function, available only in shim mode.

// importMap will be an object in the same shape as the json in a importmap script
const importMap = { imports: {/*...*/}, scopes: {/*...*/} };

importShim.addImportMap(importMap);

Dynamic Import

Stability: Stable browser standard

Dynamic import(...) within any modules loaded will be rewritten as importShim(...) automatically providing full support for all es-module-shims features through dynamic import.

To load code dynamically (say from the browser console), importShim can be called similarly:

importShim('/path/to/module.js').then(x => console.log(x));

import.meta.url

Stability: Stable browser standard

import.meta.url provides the full URL of the current module within the context of the module execution.

modulepreload

Stability: WhatWG Standard, Single Browser Implementer

Preloading of modules can be achieved by including a <link rel="modulepreload" href="/module.js" /> tag in the HTML or injecting it dynamically.

This tag also supports the "integrity", "crossorigin" and "referrerpolicy" attributes as supported on module scripts.

This tag just initiates a fetch request in the browser and thus works equally as a preload polyfill in both shimmed and unshimmed modes, with integrity validation support.

Unlike the browser specification, the modulepreload polyfill does not request dependency modules by default, in order to avoid unnecessary code analysis in the polyfill scenarios. It is recommended to preload deep imports anyway so that this feature shouldn't be necessary.

Preload shim

When in shim mode, <link rel="modulepreload-shim" href="/module.js" /> must be used to properly cache the preloaded modules.

CSP Support

By default ES Module Shims provides full support for CSP by using the asm.js ES Module Lexer build. This is absolutely identical in performance to the Wasm version in Firefox and Chrome, while in Safari the asm.js version is actually faster than Wasm making this build preferable.

The CSP nonce to use for module scripts will be picked up from the first script on the page or via the nonce init option.

A full example of such a CSP workflow is provided below:

<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-n0nce'" />
<script async src="es-module-shims.js"></script>
<script type="importmap" nonce="n0nce">
{
  "pkg": "/pkg.js"
}
</script>
<script type="module" nonce="n0nce">
import pkg from 'pkg';
</script>

Wasm Build

To use the Web Assembly / non-CSP build of ES Module Shims, this is available as a self-contained single file at es-module-shims/wasm or es-module-shims/dist/es-module-shims.wasm.js in the package folder.

JSON Modules

Stability: WhatWG Standard, Single Browser Implementer

In shim mode, JSON modules are always supported. In polyfill mode, JSON modules require the polyfillEnable: ['json-modules'] init option.

JSON Modules are currently supported in Chrome when using them via an import assertion:

<script type="module">
import json from 'https://site.com/data.json' assert { type: 'json' };
</script>

In addition JSON modules need to be served with a valid JSON content type.

Checks for assertion failures are not currently included.

CSS Modules

Stability: WhatWG Standard, Single Browser Implementer

In shim mode, CSS modules are always supported. In polyfill mode, CSS modules require the polyfillEnable: ['css-modules'] init option.

CSS Modules are currently supported in Chrome when using them via an import assertion:

<script type="module">
import sheet from 'https://site.com/sheet.css' assert { type: 'css' };
</script>

To support the polyfill or shim of this feature, the Constructable Stylesheets polyfill must be separately included in browsers not supporting Constructable Stylesheets eg via:

<script async src="https://unpkg.com/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.js"></script>

For more information see the web.dev article.

In addition CSS modules need to be served with a valid CSS content type.

Checks for assertion failures are not currently included.

Resolve

Stability: Draft HTML PR

import.meta.resolve provides a contextual resolver within modules. It is synchronous, changed from being formerly asynchronous due to following the browser specification PR.

The second argument to import.meta.resolve permits a custom parent URL scope for the resolution (not currently in the browser spec), which defaults to import.meta.url.

// resolve a relative path to a module
var resolvedUrl = import.meta.resolve('./relative.js');
// resolve a dependency from a module
var resolvedUrl = import.meta.resolve('dep');
// resolve a path
var resolvedUrlPath = import.meta.resolve('dep/');
// resolve with a custom parent scope
var resolvedUrl = import.meta.resolve('dep', 'https://site.com/another/scope');

Node.js also implements a similar API, although it's in the process of shifting to a synchronous resolver.

Module Workers

ES Module Shims can be used in module workers in browsers that provide dynamic import in worker environments, which at the moment are Chrome(80+), Edge(80+), Safari(15+).

An example of ES Module Shims usage in web workers is provided below:

/**
 * 
 * @param {string} aURL a string representing the URL of the module script the worker will execute.
 * @returns {string} The string representing the URL of the script the worker will execute.
 */
function getWorkerScriptURL(aURL) {
  // baseURL, esModuleShimsURL are considered to be known in advance
  // esModuleShimsURL - must point to the non-CSP build of ES Module Shims, 
  // namely the `es-module-shim.wasm.js` output: es-module-shims/dist/es-module-shims.wasm.js

  return URL.createObjectURL(new Blob(
    [
      `importScripts('${new URL(esModuleShimsURL, baseURL).href}');
      importShim.addImportMap(${JSON.stringify(importShim.getImportMap())});
      importShim('${new URL(aURL, baseURL).href}').catch(e => setTimeout(() => { throw e; }))`
    ],
    { type: 'application/javascript' }))
}

const worker = new Worker(getWorkerScriptURL('myEsModule.js'));

For now, in web workers must be used the non-CSP build of ES Module Shims, namely the es-module-shim.wasm.js output: es-module-shims/dist/es-module-shims.wasm.js.

Init Options

Provide a esmsInitOptions on the global scope before es-module-shims is loaded to configure various aspects of the module loading process:

<script>
window.esmsInitOptions = {
  // Enable Shim Mode
  shimMode: true, // default false
  // Enable newer modules features
  polyfillEnable: ['css-modules', 'json-modules'], // default empty
  // Custom CSP nonce
  nonce: 'n0nce', // default is automatic detection
  // Don't retrigger load events on module scripts
  noLoadEventRetriggers: true, // default false
  // Skip source analysis of certain URLs for full native passthrough
  skip: /^https:\/\/cdn\.com/, // defaults to null
  // Clean up blob URLs after execution
  revokeBlobURLs: true, // default false
  // Secure mode to not support loading modules without integrity (integrity is always verified though)
  enforceIntegrity: true, // default false
  // Permit overrides to import maps
  mapOverrides: true, // default false

  // -- Hooks --
  // Module load error
  onerror: (e) => { /*...*/ }, // default noop
  // Called when polyfill mode first engages
  onpolyfill: () => {}, // default logs to the console
  // Hook all module resolutions
  resolve: (id, parentUrl, resolve) => resolve(id, parentUrl), // default is spec resolution
  // Hook source fetch function
  fetch: (url, options) => fetch(url, options), // default is native
  // Hook import.meta construction
  meta: (meta, url) => void // default is noop
  // Hook top-level imports
  onimport: (url, options, parentUrl) => void // default is noop
}
</script>
<script async src="es-module-shims.js"></script>

<script type="esms-options"> can also be used:

<script type="esms-options">
{
  "shimMode": true,
  "polyfillEnable": ["css-modules", "json-modules"],
  "nonce": "n0nce",
  "onpolyfill": "polyfill"
}
</script>

This can be convenient when using a CSP policy. Function strings correspond to global function names.

Shim Mode Option

Shim Mode can be overridden using the shimMode option:

<script type="esms-options">
{
  "shimMode": true
}
</script>

For example, if lazy loading <script type="module-shim"> scripts alongside static native module scripts, shim mode would not be enabled at initialization time.

DOM load events are fired for all "module-shim" scripts both for success and failure just like for native module scripts.

Pollyfill Enable Option

The polyfillEnable option allows enabling polyfill features which are newer and would otherwise result in unnecessary polyfilling in modern browsers that haven't yet updated.

Currently this option supports just "css-modules" and "json-modules".

<script type="esms-options">
{
  "polyfillEnable": ["css-modules", "json-modules"]
}
</script>

The above is necessary to enable CSS modules and JSON modules.

Baseline Support Analysis Opt-Out

The reason the polyfillEnable option is needed is because ES Module Shims implements a performance optimization where if a browser supports modern modules features to an expected baseline of import maps support, it will skip all polyfill source analysis resulting in full native passthrough performance.

If the application code then tries to use modern features like CSS modules beyond this baseline it won't support those features. As a result all modules features which are considered newer or beyond the recommended baseline require explicit enabling. This common baseline itself will change to track the common future modules baseline supported by this project for each release cycle.

This option can also be set to true to entirely disable the native passthrough system and ensure all sources are fetched and analyzed through ES Module Shims. This will still avoid duplicate execution since module graphs are still only reexecuted when they use unsupported native features, but there is a small extra cost in doing the analysis.

Enforce Integrity

When enabled, enforceIntegrity will ensure that all modules loaded through ES Module Shims must have integrity defined either on a <link rel="modulepreload" integrity="..."> or on a <link rel="modulepreload-shim" integrity="..."> preload tag in shim mode. Modules without integrity will throw at fetch time.

For example in the following, only the listed app.js and dep.js modules will be able to execute with the provided integrity:

<script type="esms-options">{ "enforceIntegrity": true }</script>
<link rel="modulepreload-shim" href="/app.js" integrity="sha384-..." />\
<link rel="modulepreload-shim" href="/dep.js" integrity="sha384-..." />
<script type="module-shim">
  import '/app.js';
</script>

Strong execution guarantees are only possible in shim mode since in polyfill mode it is not possible to stop the native loader from executing code without an integrity.

Future versions of this option may provide support for origin-specific allow lists.

Nonce

The nonce option allows setting a CSP nonce to be used with all script injections for full CSP compatibility supported by the CSP build of ES Module Shims.

Alternatively, add a blob: URL policy with the CSP build to get CSP compatibility.

<script type="esms-options">
{
  "nonce": "n0nce"
}
</script>

No Load Event Retriggers

Because of the extra processing done by ES Module Shims it is possible for static module scripts to execute after the DOMContentLoaded or readystatechange events they expect, which can cause missed attachment.

In order to ensure libraries that rely on these event still behave correctly, ES Module Shims will always double trigger these events that would normally have executed before the document ready state transition to completion, once all the static module scripts in the page have been completely executed through ES module shims.

In such a case, this double event firing can be disabled with the noLoadEventRetriggers option:

<script type="esms-options">
{
  // do not re-trigger DOM events (onreadystatechange, DOMContentLoaded)
  "noLoadEventRetriggers": true
}
</script>
<script async src="es-module-shims.js"></script>

Skip Processing

When loading modules that you know will only use baseline modules features, it is possible to set a rule to explicitly opt-out modules from rewriting. This improves performance because those modules then do not need to be processed or transformed at all, so that only local application code is handled and not library code.

This can be configured by providing a URL regular expression for the skip option:

<script type="esms-options">
{
  "skip": "/^https?:\/\/(cdn\.skypack\.dev|jspm\.dev)\//"
}
</script>
<script async src="es-module-shims.js"></script>

Revoke Blob URLs

When polyfilling the missing features es-module-shims would create in-memory blobs using URL.createObjectURL() for each processed module. In most cases, memory footprint of these blobs is negligible so there is no need to call URL.revokeObjectURL() for them, and we don't do that by default.

That said, in some scenarios, e.g. when evaluating some continuously changing modules without a page reload, like in a web-based code editor, you might want to reduce the growth of memory usage by revoking those blob URLs after they were already imported.

You can do that by enabling the revokeBlobURLs init option:

<script type="esms-options">
{
  "revokeBlobURLs": true
}
</script>
<script type="module" src="es-module-shims.js"></script>

NOTE: revoking object URLs is not entirely free, while we are trying to be smart about it and make sure it doesn't cause janks, we recommend enabling this option only if you have done the measurements and identified that you really need it.

Overriding import map entries

When dynamically injecting import maps, an error will be thrown in both polyfill and shim modes if the new import map would override existing entries with a different value.

It is possible to disable this behavior in shim mode by setting the mapOverrides option:

<script type="esms-options">
{
  "shimMode": true,
  "mapOverrides": true
}
</script>
<script type="importmap-shim">
{
  "imports": {
    "x": "/x.js"
  }
}
</script>
<script>
// No error will be thrown here
document.body.appendChild(Object.assign(document.createElement('script'), {
  type: 'importmap',
  innerHTML: JSON.stringify({ imports: { x: './y.js' } }),
}));
</script>

This can be useful for HMR workflows.

Hooks

Polyfill hook

The polyfill hook is called when running in polyfill mode and the polyfill is kicking in instead of passing through to the native loader.

This can be a useful way to verify that the native passthrough is working correctly in latest browsers for performance, while also allowing eg the ability to analyze or get metrics reports of how many users are getting the polyfill actively applying to their browser application loads.

<script>
window.polyfilling = () => console.log('The polyfill is actively applying');
</script>
<script type="esms-options">
{
  "onpolyfill": "polyfilling"
}
</script>

The default hook will log a message to the console with console.info noting that polyfill mode is enabled and that the native error can be ignored.

Overriding this hook with an empty function will disable the default polyfill log output.

In the above, running in latest Chromium browsers, nothing will be logged, while running in an older browser that does not support newer features like import maps the console log will be output.

Error hook

You can provide a function to handle errors during the module loading process by providing an onerror option:

<script>
  window.esmsInitOptions = {
    onerror: error => console.log(error) // defaults to `((e) => { throw e; })`
  }
</script>
<script async src="es-module-shims.js"></script>

Import Hook

The import hook is supported for both shim and polyfill modes and provides an async hook which can ensure any necessary work is done before a top-level module import or dynamic import() starts further processing.

<script>
  window.esmsInitOptions = {
    onimport: function (url, options, parentUrl) {
      console.log(`Top-level import for ${url}`);
    }
  }
</script>

Resolve Hook

The resolve hook is supported for both shim and polyfill modes and allows full customization of the resolver, while still having access to the original resolve function.

Note that in polyfill mode the resolve hook may not be called for all modules when native passthrough is occurring and that it still will not affect the native passthrough executions.

If the resolve hook should apply for all modules in the entire module graph, make sure to set polyfillEnable: true to disable the baseline support analysis opt-out.

<script>
  window.esmsInitOptions = {
    shimMode: true,
    resolve: function (id, parentUrl, defaultResolve) {
      if (id === 'custom' && parentUrl.startsWith('https://custom.com/'))
        return 'https://custom.com/custom.js';

      // Default resolve will handle the typical URL and import map resolution
      return defaultResolve(id, parentUrl);
    }
  }
</script>

Support for an asynchronous resolve hook has been deprecated as of 1.5.0 and will be removed in the next major.

Instead async work should be done with the import hook.

Meta Hook

The meta hook allows customizing the import.meta object in each module scope.

The function takes as arguments the import.meta object itself (with import.meta.url an import.meta.resolve already present), and the URL of the module as its second argument.

Example:

<script>
  window.esmsInitOptions = {
    shimMode: true,
    meta: function (metaObj, url) {
      metaObj.custom = `custom value for ${url}`;
    }
  }
</script>

Where within the module the following would be supported:

import assert from 'assert';
assert.ok(import.meta.custom.startsWith('custom value'));

Fetch Hook

The fetch hook is supported for shim mode only.

The ES Module Shims fetch hook can be used to implement transform plugins.

For example TypeScript support:

<script>
  window.esmsInitOptions = {
    shimMode: true,
    fetch: async function (url, options) {
      const res = await fetch(url, options);
      if (!res.ok)
        return res;
      if (res.url.endsWith('.ts')) {
        const source = await res.body();
        const transformed = tsCompile(source);
        return new Response(new Blob([transformed], { type: 'application/javascript' }));
      }
      return res;
    } // defaults to `((url, options) => fetch(url, options))`
  }
</script>
<script async src="es-module-shims.js"></script>

Because the dependency analysis applies by ES Module Shims takes care of ensuring all dependencies run through the same fetch hook, the above is all that is needed to implement custom plugins.

Streaming support is also provided, for example here is a hook with streaming support for JSON:

window.esmsInitOptions = {
  shimMode: true,
  fetch: async function (url, options) {
    const res = await fetch(url, options);
    if (!res.ok || !/^application\/json($|;)/.test(res.headers.get('content-type')))
      return res;
    const reader = res.body.getReader();
    const headers = new Headers(res.headers);
    headers.set('Content-Type', 'application/javascript');
    return new Response(new ReadableStream({
      async start (controller) {
        let done, value;
        controller.enqueue(new TextEncoder.encode('export default '));
        while (({ done, value } = await reader.read()) && !done) {
          controller.enqueue(value);
        }
        controller.close();
      }
    }), { headers });
  }
}

Implementation Details

Import Rewriting

  • Sources are fetched, import specifiers are rewritten to reference exact URLs, and then executed as BlobURLs through the whole module graph.
  • The lexer handles the full language grammar including nested template strings, comments, regexes and division operator ambiguity based on backtracking.
  • When executing a circular reference A -> B -> A, a shell module technique is used to "shim" the circular reference into an acyclic graph. As a result, live bindings for the circular parent A are not supported, and instead the bindings are captured immediately after the execution of A.

Inspiration

Huge thanks to Rich Harris for inspiring this approach with Shimport.

Author: guybedford
Source Code: https://github.com/guybedford/es-module-shims 
License: MIT license

#javascript #modules