Skip to main content

Module Resolution

NPM Modules

Bare Module Imports

In LiveCodes you can use node-style bare module imports for npm modules like you do in your local development. However, there are no installation or build steps required.

e.g. consider the following code:

import { v4 } from 'uuid';

document.body.innerHTML = v4();

If you run it directly in the browser, you get this error:

Uncaught TypeError: Failed to resolve module specifier "uuid". Relative references must start with either "/", "./", or "../".

However, in LiveCodes, bare module imports are transformed to full URLs that are imported from CDN (by default: esm.sh) which provides ESM versions of NPM packages.

import { v4 } from 'uuid';
becomes
import { v4 } from 'https://esm.sh/uuid';

This is made possible by using import maps.

Demo:

show code
import { createPlayground } from 'livecodes';

const options = {
"params": {
"js": "import { v4 } from 'uuid';\n\ndocument.body.innerHTML = v4();"
}
};
createPlayground('#container', options);

 

You can import React like that:

import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';

Demo:

show code
import { createPlayground } from 'livecodes';

const options = {
"template": "react"
};
createPlayground('#container', options);

It just works without a build step and without you having to worry about. And when you export your project to another service (e.g. CodePen) or as HTML, the full URL imports are used, so your code continues to work.

tip

It is recommended to use this method for dependencies over using external scripts. The dependencies are explicitly stated in the code. And if you move to a local development environment, your bundler will take care of importing them and doing other optimizations like tree-shaking.

CommonJS Modules

CommonJS module requires are also supported (they are converted to ESM imports).

So this also works (although not recommended - use ESM imports instead):

const { v4 } = require('uuid');

document.body.innerHTML = v4();

Exercise:

Copy the previous code snippet and paste it in the playground below. Check the generated code in the compiled code viewer.

show code
import { createPlayground } from 'livecodes';

const options = {
"params": {
"activeEditor": "script",
"compiled": "open"
}
};
createPlayground('#container', options);

info

Script code that contains import, export or require gets served in a script tag with type="module".

NPM packages can be searched and added as script tags from the External Resources screen.

Deno Modules

Modules imported from deno.land/x (or any other URL ending in .ts, .jsx or .tsx) are automatically transpiled (ts -> js) and bundled by bundlejs (using esbuild), including their relative imports. The project on LiveCodes that imports these modules does not need to be using TypeScript.

Example:

import { uuid } from 'https://deno.land/x/uuid/mod.ts';

document.body.innerHTML = uuid();

Open in LiveCodes

JSR Modules

Modules can be imported from jsr.io using the prefix jsr:. The project on LiveCodes that imports these modules does not need to be using TypeScript.

Example:

import { yassify } from 'jsr:@kwhinnery/yassify';

document.body.innerHTML = yassify('Hello, World!');

Open in LiveCodes

GitHub/GitLab/Bitbucket

Modules can also be similarly imported from GitHub, Gitlab or Bitbucket. Also these imports are transpiled and bundled (see Deno Modules).

import { flatten } from 'https://github.com/remeda/remeda/blob/master/src/flatten.ts';

console.log(flatten([[1, 2], [3], [4, 5]])); // -> [1, 2, 3, 4, 5]

Open in LiveCodes

tip

If you do not want the import URL to be bundled (e.g. in Deno or GitHub imports), add #nobundle to the end of URL.

Example:

import { flatten } from 'https://github.com/remeda/remeda/blob/master/src/flatten.ts#nobundle';

If you want to bundle (and transpile) any import URL, prefix it with bundle: (see below).

CDN Providers

By default, npm modules are imported from esm.sh. You may choose another provider by using a CDN prefix. These are examples of importing the library uuid:

uuidhttps://esm.sh/uuid (info)

esm.sh:uuidhttps://esm.sh/uuid (info)

skypack:uuidhttps://cdn.skypack.dev/uuid (info)

jsdelivr:uuidhttps://cdn.jsdelivr.net/npm/uuid (info)

esm.run:uuidhttps://esm.run/uuid (info)

unpkg:uuidhttps://unpkg.com/uuid?module (info)

esbuild:uuidhttps://esbuild.vercel.app/uuid (info)

bundlejs:uuidhttps://deno.bundlejs.com/?file&q=uuid (info)

bundle:uuidhttps://deno.bundlejs.com/?file&q=uuid (info)

deno:uuidhttps://deno.bundlejs.com/?file&q=https://deno.land/x/uuid/mod.ts (info)

npm:uuidhttps://esm.sh/uuid (info)

node:uuidhttps://esm.sh/uuid (info)

jsr:@std/uuidhttps://esm.sh/jsr/@std/uuid (info)

jspm:uuidhttps://jspm.dev/uuid (info - DEPRECATED)

Example:

import React, { useState } from 'esm.sh:react';
import { createRoot } from 'esm.sh:react-dom/client';
caution

Please note that importing the same module (even for dependencies) from different CDNs may cause conflicts.

Example:

// this will NOT work!
import React, { useState } from 'esm.sh:react'; // React from esm.sh
import { createRoot } from 'react-dom/client'; // React from jspm.dev

Change Default CDN

Default CDN can be changed on project-level using the custom settings property defaultCDN which accepts a string representing one of the CDN aliases listed above.

Example: This assigns Skypack as the default CDN for all imports of the project

{
"defaultCDN": "skypack"
}

Package Version

Most CDN providers allow specifying package version using the format:
{pkgName}@{version}/{path}.

Example:

import latest from 'lodash';
import v3 from 'lodash@3';

console.log(latest.VERSION); // -> 4.17.21
console.log(v3.VERSION); // -> 3.10.1

Custom Module Resolution

Module resolution described in this page mainly depends on import maps. The generated import map is added to the result page.

You may wish to override or customize module resolution behavior (e.g. change URL, CDN, specify version, import custom unpublished library, ...etc. ), however you cannot add another import map script because currently multiple import maps are not yet supported.

LiveCodes allows you to add your custom import map by one of the following methods:

Custom Settings

In the standalone app, via the custom settings property imports.

Example:

Custom Settings
{
"imports": {
"my-lib": "https://my-server.com/path/to/library.js"
}
}

SDK

For embedded playgrounds, use the SDK embed option config.imports.

Example:

index.js
import { createPlayground } from 'livecodes';

const config = {
imports: {
'my-lib': 'https://my-server.com/path/to/library.js',
},
// other configurations ...
};

createPlayground('#container', { config });

Please note that you may also provide custom type definitions for your custom modules for editor intellisense and better development experience.