GithubHelp home page GithubHelp logo

imd's Introduction

Imports Module Definition

IMD is an implementation of the AMD specification that performs absolutely no loading. The primary goal of it is to play nice with HTML Imports, but it should work well with any code loader that doesn't mandate a particular module registry.

Why IMD?

JavaScript module systems generally perform three different tasks:

  1. Definition Allow module authors to define an encapsulated unit of code, including what other modules it depends on.
  2. Resolving Given a module reference, resolve it to an actual module instance. This typically involves a central module registry that maps module names to instances.
  3. Loading Given a module reference that is not yet loaded into the registry, load it from some source, usually a URL (via an XHR).

IMD only performs the first two tasks, in a way that's fully compliant with the AMD spec.

This is the minimal module system needed if you're already loaded your script resources via HTML Imports. HTML Imports handily takes care of loading resources and their transitive dependencies, de-duplicating imports, and executing scripts in the correct order.

Together, IMD and HTML Imports form a really great module system. Some of the benefits over RequireJS include:

  • IMD is extremely small. With no loading code, IMD is almost entirely just a AMD-compiant registry in just 150 lines of code (with comments).
  • A module defined in an HTML Import can be sure its non-script resources, like CSS and HTML templates, have been loaded as well.
  • Browsers with native HTML Import support can aggressively pre-scan and pre-load HTML Imports by reading the <link> tags.
  • Servers that support HTTP/2 Push can easily read <link> tags and preemptively push dependencies, resulting in very fast load times.

What about ES6 (ES2015) Modules?

They're great. Really, we can't wait for them to be implemented natively in browsers. And until then, compilers and loaders like SystemJS and Babel do allow developers to use ES6 modules now, if they're willing to deal with a build step.

Not every project can or wishes to do so, and HTML Imports is not a JavaScript module definition system, so IMD is an extremely lightweight way to use modules on top of imports.

When the ES6 module loader spec is further along, we will look into ways of integrating the two so that JavaScript can import HTML "modules" and vice-versa. We're very excited about the possibilities for interop.

How Do I?

Download and Include IMD

IMD is distributed as an HTML Import-able HTML file, naturally. Install and uselike this:

Install:

> bower install PolymerLabs/IMD --save

Import:

<link rel="import" href="../imd/imd.html">

We recommend that HTML files that require or define do not directly import IMD, but rather let the main page import IMD, usually as the very first import. This is so that an application that really requires RequireJS to load modules (this can be true when loading pure JS modules with no corresponding <script> tags), can setup RequireJS instead of IMD. Since IMD is fully AMD compliant, all modules defined in HTML imports will work just fine.

Define a Module

Modules are defined exactly as in other AMD systems like RequireJS: Public modules are defined by name:

Here's the definition of a mythical module, 'squidbits', that depnds on the modules 'tentacles.html', and 'ink':

define('squidbits', ['./tentacles.html', 'ink'], function(tentacles, ink) {
  return {tentacles: tentacles, ink: ink, squidbits: true};
});

Now, since IMD is targeted at projects already using HTML Imports, it's likely that the module will be defined inside an HTML file, like so:

<link rel="import" href="./tentacles.html">
<script src="ink.js"></script>

<script>
define('squidbits', ['./tentacles.html', 'ink'], function(tentacles, ink) {
  return {tentacles: tentacles, ink: ink, squidbits: true};
});
</script>

Notice the <link> and <script> tags. These tell the browser to load 'tentacles.html' and 'ink.js'. Because scripts are blocked until imports and other scripts have loaded and run, and 'tentacles.html' and 'ink.js' define modules, squidbits's dependencies are guaranteed to be loaded and registered when the inline script runs.

Note that we're assuming that ink.js defines a ink module here, and tentacles.html defines an anonymous module.

Define Anonymous / Relative Modules

Private (relative) module names are inferred from the current import:

tentacles.html:

<script>
define(function() {
  return /* module contents */;
})
</script>

This module is available at a relative URL, as shown in the above squidbits example. There can be only one anonymous module per HTML document.

If you want to use an existing anonymous module (say, something defined following the UMD pattern), give it a name with the as attribute on a <script> tag:

<script src="thingo.js" as="thingy"></script>

Future work

HTML dependencies.

Imagine:

foo.html:

<template id="bar">...</template>

You could import a document: index.html:

define(['foo.html'], function(foo) {
  // foo is a document
  let bar = foo.querySelector('#bar');
  document.appendChild(document.importNode(bar.content));
})

Or a node directly: index.html:

define(['foo.html#bar'], function(bar) {
  // bar is a HTMLTemplate node!
  document.appendChild(document.importNode(bar.content));
})

Reduced import/define duplication

The one downside of IMD relative to RequireJS is that dependencies often appear twice in a file: once as a HTML Import and one in the define() call. We could conceivably infer the dependency list from the imports so that there's no duplication.

ES6

There is a lot to explore with ES6 module loading and HTML Imports. The loading and ordering semantics appear to be fully compatible, and given a configurable enough loader we should be able to let ES6 modules import HTML nodes and vice-versa.

imd's People

Contributors

antonmoiseev avatar justinfagnani avatar mzdv avatar nevir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imd's Issues

Doesn't work well with vulcanize

We've been using IMD for awhile and one of the issues we faced, it doesn't work well with vulcanize. IMD allows only one anonymous module per HTML document. Scripts that back Polymer elements usually remain anonymous, so after vulcanization the bundle contains multiple anonymous modules and IMD throws an error at runtime.

Automatically add js extension for relative module IDs

What do you think about automatically adding .js extension while resolving relative module IDs? Relative URLs always represent a file so it should be safe to append it.

Motivation

We use TypeScript and ES6 modules for writing application code. For importing local modules we use relative paths:

import Logger from './lib/logger';

After transpiling it turns into an AMD module:

define(["require", "exports", './lib/logger'], callbackFn);

The module itself is loaded as part of an HTML Import:

<script src="lib/logger.js"></script>

And registered within the module registry with following name:

http://localhost:3000/lib/logger.js

However when IMD attempts to resolve the imported module it cannot be found:

The module "http://localhost:3000/lib/logger" has not been loaded

If we specify .js extension as part of the import statement it breaks the tooling since original file has .ts extension.

Create/publish a new release of package on Bower

IMD is distributed as a Bower package. In order for users to receive
bug fixes, updates, etc new versions of the library must be released
periodically. It's particularly important to release a new version after
critical bug fixes.

Before commit 6021053 (issue #9) the library was fundamentally broken in
Firefox/Safari. There have been no new releases since this commit so
the version distributed on Bower currently doesn't work in those
browsers.

The semver for the package should be updated, and a new tag/release created so users can install the latest version of the library from Bower.

Thanks for your time (^_^)

Out of order dependencies should work

webcomponentjs's HTMLImport polyfills don't guarantee what order js files are evaluated. So relying on module definitions already being there might not be safe. The AMD spec also hints at this:

Multiple define calls can be made within a single script. The order of the define calls SHOULD NOT be
significant. Earlier module definitions may specify dependencies that are defined later in the same
script. It is the responsibility of the module loader to defer loading unresolved dependencies until the
entire script is loaded to prevent unnecessary requests.

So ... we're not loading, but it may make sense that defines should be generally allowed to be out of order.

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.