@plnkr/runtime

No webpack, no parcel, no rollup, no npm, no friction. Just your code and your imagination.

Usage no npm install needed!

<script type="module">
  import plnkrRuntime from 'https://cdn.skypack.dev/@plnkr/runtime';
</script>

README

@plnkr/runtime

No webpack, no parcel, no rollup, no npm, no friction. Just your code and your imagination.

A browser-native tool for running modern javascript code, using npm dependencies without any tooling. Supports hot module reloading and css / less imports (more to come).

This is not for production, this is for experimentation without boilerplate overload or for use in niche developer tools like Plunker. Everything is loaded on the fly and, of course, this will impose certain performance limitations.

Usage

To get a hold of an instance of this module, all you need to do is:

Using the amazing jspm.io cdn:

import('https://dev.jspm.io/@plnkr/runtime')
    .then(esModule => esModule.default)
    .then(PlnkrRuntime => {
        // Let your imagination go wild
    });

or using a popular cdn that fronts npm releases like unpkg:

<script src="https://unpkg.com/@plnkr/runtime"></script>
<script>
    const PlnkrRuntime = window.PlnkrRuntime;
    // Get weird
</script>

Example

This example demonstrates an example where we define a custom react Component, pull this into another file and render it to a string using react-dom.

Note: No npm, no webpack, no parcel, no configuration, no friction. Just code and your imagination.

// We define a mock 'host' filesystem that represents the project we will run
const files = {
    'package.json': JSON.stringify({
        dependencies: {
            react: '16.x',
            'react-dom': '16.x',
        },
    }),
    'index.js': `
        import React from 'react';
        import { renderToString } from 'react-dom/server';

        import Hello from './Hello';

        export const markup = renderToString(<Hello name="World"></Hello>);
    `,
    'Hello.js': `
        import React, { Component } from 'react';

        export default class Hello extends Component {
            render() {
                return <h1>Hello {this.props.name}</h1>;
            }
        }
    `,
};
// Next, we define a host that implements the RuntimeHost interface and resolves files from our mock filesystem
const host = {
    getCanonicalPath(path) {
        if (files[path]) return path;
        if (files[`${path}.js`]) return `${path}.js`;
        return Promise.reject(new Error(`File not found ${path}`));
    },
    getFileContents(canonicalPath) {
        return files[canonicalPath];
    }
};
// Now that we have a host, we can create a runtime instance
const runtime = new PlnkrRuntime.Runtime({ host });

// Now we run our example code that will pull in react and react-dom, will transpile our custom code and will
// then execute it in a context where bare modules are resolved for us.
const { markup } = await runtime.import('./index.js');

API

new PlnkrRuntime.Runtime({ host })

Creates a new Runtime instance where:

runtime.import(key: string, parentKey?: string): Promise<ModuleInstance>

Import and run the the code from the canonical url determined by running runtime.resolve(key, parentKey).

Returns a Promise that will resolve to the module instance.

runtime.invalidate(...keys: string[]): Promise<void>

Invalidate the module instances, traversing up to all dependent modules and invalidating those as well where:

Returns a Promise that will resolve when all requested modules and their dependents have been invalidated.

runtime.resolve(key: string, parentKey?: string): Promise<string>

Resolve absolute and relative paths and urls as well as bare module specifiers to their canonical url where:

Returns a Promise that will resolve to the resolved, canonical url.

RuntimeHost

This is the interface that must be implemented by the host object passed to new PlnkrRuntime.Runtime({ host }).

RuntimeHost.getCanonicalPath?(key: string): string | PromiseLike<string>

Optional

Return the canonical path or a Promise that resolves for a given 'local' resource. A 'local' resource is one that is neither a bare module nor a url whose prefix doesn't match document.baseURI. This method should be implemented if you want to support importing relative files without their extensions and these can't be determined a priori.

RuntimeHost.getFileContents(key: string): string | PromiseLike<string>

Return the contents of the file (or a Promise thereof) whose canonical path is key.

Note: This interface will be called to resolve bare module versions with package.json as the key. If you want to control the versions of bare modules (npm modules), then a mock package.json can be returned here that defined the dependencies for the bare modules whose versions are important to you.

Thank you

This project was made possible by:

  • All the hard work by the collaborators of es-module-loader.
  • Guy Bedford and his jspm project and its 'magic' ES Module and System.register CDNs, dev.jspm.io and system-dev.jspm.io, respectively.