Git Product home page Git Product logo

esm.sh's Introduction

esm.sh

esm.sh

A fast, smart, & global content delivery network (CDN) for modern(es2015+) web development.

Release Discord Twitter Github Sponsors Open Collective

How to Use

esm.sh is a modern CDN that allows you to import es6 modules from a URL:

import Module from "https://esm.sh/PKG@SEMVER[/PATH]";

or build a module with custom input(code):

import { esm } from "https://esm.sh/build";

const { sayHi } = await esm`
  import chalk from "chalk";
  export const sayHi = () => chalk.blue("Hi!");
`;
console.log(sayHi()); // prints "Hi!" message in blue color

More usage check out here.

You may want to use bare specifier instead of URL with import maps:

<script type="importmap">
  {
    "imports": {
      "react": "https://esm.sh/[email protected]"
    }
  }
</script>
<script type="module">
  import React from "react" // alias to https://esm.sh/[email protected]
</script>

Importing from NPM

import React from "https://esm.sh/[email protected]";

You may also use a semver or a dist-tag instead of a fixed version number, or omit the version/tag entirely to use the latest tag:

import React from "https://esm.sh/react";        // 18.2.0 (latest)
import React from "https://esm.sh/react@^17";    // 17.0.2
import React from "https://esm.sh/react@canary"; // 18.3.0-canary-e1ad4aa36-20230601

You can import submodules of a package:

import { renderToString } from "https://esm.sh/[email protected]/server";

or import/fetch non-module(js) as following:

import "https://esm.sh/[email protected]/package.json" assert { type: "json" };

Importing from GitHub

esm.sh supports to import modules/assets from a github repo: /gh/OWNER/REPO[@TAG]/PATH. For example:

import tslib from "https://esm.sh/gh/microsoft/[email protected]";

or load a svg image from a github repo: https://esm.sh/gh/microsoft/fluentui-emoji/assets/Party%20popper/Color/party_popper_color.svg

Specifying Dependencies

By default, esm.sh rewrites import specifiers based on the package dependencies. To specify the version of these dependencies, you can add the ?deps=PACKAGE@VERSION query. To specify multiple dependencies, separate them with a comma, like this: [email protected],[email protected].

import React from "https://esm.sh/[email protected]";
import useSWR from "https://esm.sh/[email protected]";

Aliasing Dependencies

import useSWR from "https://esm.sh/swr?alias=react:preact/compat";

in combination with ?deps:

import useSWR from "https://esm.sh/swr?alias=react:preact/compat&[email protected]";

The origin idea was coming from @lucacasonato.

Tree Shaking

By default, esm.sh exports a module with all its exported members. However, if you want to import only a specific set of members, you can specify them by adding a ?exports=foo,bar query to the import statement.

import { __await, __rest } from "https://esm.sh/tslib"; // 7.3KB
import { __await, __rest } from "https://esm.sh/tslib?exports=__await,__rest"; // 489B

By using this feature, you can take advantage of tree shaking with esbuild and achieve a smaller bundle size. Note that this feature is only supported for ESM modules and not CJS modules.

Bundle Mode

import { Button } from "https://esm.sh/antd?bundle";

In bundle mode, all dependencies are bundled into a single JS file except the peer dependencies.

Development Mode

import React from "https://esm.sh/react?dev";

With the ?dev option, esm.sh builds a module with process.env.NODE_ENV set to "development" or based on the condition development in the exports field of package.json. This is useful for libraries that have different behavior in development and production. For example, React will use a different warning message in development mode.

ESBuild Options

By default, esm.sh checks the User-Agent header to determine the build target. You can also specify the target by adding ?target, available targets are: es2015 - es2022, esnext, deno, denonext, node and bun.

import React from "https://esm.sh/react?target=es2020";

Other supported options of esbuild:

  • Conditions
    import foo from "https://esm.sh/foo?conditions=custom1,custom2";
  • Keep names
    import foo from "https://esm.sh/foo?keep-names";
  • Ignore annotations
    import foo from "https://esm.sh/foo?ignore-annotations";

Web Worker

esm.sh supports ?worker query to load the module as a web worker:

import workerFactory from "https://esm.sh/monaco-editor/esm/vs/editor/editor.worker?worker";

const worker = workerFactory();

You can pass some custom code snippet to the worker when calling the factory function:

const workerAddon = `
self.onmessage = function (e) {
  console.log(e.data)
}
`;
const worker = workerFactory(workerAddon);

Package CSS

<link rel="stylesheet" href="https://esm.sh/monaco-editor?css">

This only works when the package imports CSS files in JS directly.

Importing WASM Modules

esm.sh supports importing wasm modules in JS directly, to do that, you need to add ?module query to the import URL:

import wasm from "https://esm.sh/@dqbd/[email protected]/tiktoken_bg.wasm?module";

const { exports } = new WebAssembly.Instance(wasm, imports);

Fixing Named Exports

If you get an error like ...not provide an export named..., that means esm.sh can't resolve named exports of the module correctly. You can add ?exports=foo,bar query to specify the named exports:

import { render } from "https://esm.sh/[email protected]?exports=render";

Using Import Maps

Import Maps has been supported by most modern browsers and Deno natively. This allows bare import specifiers, such as import React from "react", to work.

esm.sh supports ?external=foo,bar query to specify external dependencies. With this query, esm.sh will not rewrite the import specifiers of the specified dependencies. For example:

{
  "imports": {
    "preact": "https://esm.sh/[email protected]",
    "preact-render-to-string": "https://esm.sh/[email protected]?external=preact"
  }
}

Alternatively, you can mark all dependencies as external by adding a * prefix before the package name:

{
  "imports": {
    "preact": "https://esm.sh/[email protected]",
    "preact-render-to-string": "https://esm.sh/*[email protected]",
    "swr": "https://esm.sh/*[email protected]",
    "react": "https://esm.sh/[email protected]/compat"
  }
}

Import maps supports trailing slash that can not work with URL search params friendly. To fix this issue, esm.sh provides a special format for import URL that allows you to use query params with trailing slash: change the query prefix ? to & and put it after the package version.

{
  "imports": {
    "react-dom": "https://esm.sh/[email protected]?pin=v132&dev",
    "react-dom/": "https://esm.sh/[email protected]&pin=v132&dev/"
  }
}

esm.sh also provides a CLI Script in Deno to generate and update the import maps that resolves dependencies automatically.

Deno Compatibility

esm.sh is a Deno-friendly CDN that resolves Node's built-in modules (such as fs, os, net, etc.), making it compatible with Deno.

import express from "https://esm.sh/express";

const app = express();
app.get("/", (req, res) => {
  res.send("Hello World");
});
app.listen(3000);

For users using deno < 1.33.2, esm.sh uses deno.land/[email protected]/node as the node compatibility layer. You can specify a different version by adding the ?deno-std=$VER query:

import postcss from "https://esm.sh/express?deno-std=0.128.0";

Deno supports type definitions for modules with a types field in their package.json file through the X-TypeScript-Types header. This makes it possible to have type checking and auto-completion when using those modules in Deno. (link).

Figure #1

In case the type definitions provided by the X-TypeScript-Types header are incorrect, you can disable it by adding the ?no-dts query to the module import URL:

import unescape from "https://esm.sh/lodash/unescape?no-dts";

This will prevent the X-TypeScript-Types header from being included in the network request, and you can manually specify the types for the imported module.

Supporting Nodejs/Bun

Nodejs(18+) supports http imorting under the --experimental-network-imports flag. Bun doesn't support http modules yet.

We highly recommend Reejs as the runtime with esm.sh that works both in Nodejs and Bun.

Using CLI Script

esm.sh provides a CLI script for managing imports with import maps in Deno and Node/Bun (via Reejs). This CLI script automatically resolves dependencies and uses a pinned build version for stability.

To use the esm.sh CLI script, you first need to run the init command in your project's root directory:

deno run -A -r https://esm.sh init

Once you've initialized the script, you can use the following commands to manage your imports:

# Adding packages
deno task esm:add react react-dom     # add multiple packages
deno task esm:add [email protected]        # specify version
deno task esm:add react:preact/compat # using alias

# Updating packages
deno task esm:update react react-dom  # update specific packages
deno task esm:update                  # update all packages

# Removing packages
deno task esm:remove react react-dom

The CLI script works with Node/Bun via Reejs:

# Initializing
reejs x https://esm.sh init
# Using reejs tasks like deno tasks above
reejs task esm:add    react
reejs task esm:update react
reejs task esm:remove react

Building Module with Custom Input(code)

This is an experimental API that allows you to build a module with custom input(code).

  • Imports NPM/GH packages
  • Supports TS/JSX syntaxes
  • Bundle mulitple modules into a single JS file
import build from "https://esm.sh/build";

const ret = await build({
  dependencies: {
    "preact": "^10.13.2",
    "preact-render-to-string": "^6.0.2",
  },
  code: `
    /* @jsx h */
    import { h } from "preact";
    import { renderToString } from "preact-render-to-string";
    export function render(): string {
      return renderToString(<h1>Hello world!</h1>);
    }
  `,
  // for types checking and LSP completion
  types: `
    export function render(): string;
  `,
});

// import module
const { render } = await import(ret.url);
// import bundled module
const { render } = await import(ret.bundleUrl);

render(); // "<h1>Hello world!</h1>"

or use the esm tag function to build and import js/ts snippet quickly in browser with npm packages:

import { esm } from "https://esm.sh/build";

const mod = await esm`
  /* @jsx h */
  import { h } from "[email protected]";
  import { renderToString } from "[email protected]";
  export const html = renderToString(<h1>Hello world!</h1>);
`;
console.log(mod.html); // "<h1>Hello world!</h1>"

Pinning Build Version

To ensure stable and consistent behavior, you may want to pin the build version of a module you're using from esm.sh. This helps you avoid potential breaking changes in the module caused by updates to the esm.sh server.

The ?pin query allows you to specify a specific build version of a module, which is an immutable cached version stored on the esm.sh CDN.

import React from "https://esm.sh/react-dom?pin=v132";
// or use version prefix
import React from "https://esm.sh/v132/react-dom";

By using the ?pin query in the import statement, you can rest assured that the version of the module you're using will not change, even if updates are pushed to the esm.sh server. This helps ensure the stability and reliability of your application.

For UI libraries like React and Vue, esm.sh uses a special build version stable to ensure single version of the library is used in the whole application.

Global CDN

The Global CDN of esm.sh is provided by Cloudflare, one of the world's largest and fastest cloud network platforms.

Self-Hosting

To host esm.sh by yourself, check the hosting documentation.

esm.sh's People

Contributors

ije avatar jimisaacs avatar justinidlerz avatar wleonardo avatar hjaurum avatar alienzhou avatar johnpangalos avatar renhiyama avatar marktiedemann avatar marcushultman avatar kidonng avatar thaunknown avatar canrau avatar hayes avatar npg418 avatar mashaal avatar voces avatar motss avatar rivy avatar zookatron avatar goloveychuk avatar yoavbls avatar abetaev avatar hellojukay avatar lifegpc avatar loynoir avatar zhoukekestar avatar rxliuli avatar marvinhagemeister avatar lucacasonato avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.