Coder Social home page Coder Social logo

plugin-less's Introduction

SystemJS

Gitter Backers on Open Collective Sponsors on Open Collective Downloads on JS Delivr

SystemJS is a hookable, standards-based module loader. It provides a workflow where code written for production workflows of native ES modules in browsers (like Rollup code-splitting builds), can be transpiled to the System.register module format to work in older browsers that don't support native modules, running almost-native module speeds while supporting top-level await, dynamic import, circular references and live bindings, import.meta.url, module types, import maps, integrity and Content Security Policy with compatibility in older browsers back to IE11.

Sponsors

Support SystemJS by becoming a sponsor. Your logo will show up here with a link to your website.

Backers

Thank you to all our backers! ๐Ÿ™ [Become a backer]

Overview

1. s.js minimal production loader

The minimal 2.8KB s.js production loader includes the following features:

  • Loads System.register modules, the CSP-compatible SystemJS module format.
  • Support for loading bare specifier names with import maps via <script type="systemjs-importmap">.
  • Supports hooks for loader customization.

2. system.js loader

The 4.2KB system.js loader adds the following features in addition to the s.js features above:

3. system-node.cjs loader

The system-node.cjs loader is a version of SystemJS build designed to run in Node.js, typically for workflows where System modules need to be executed on the server like SSR. It has the following features:

  • Loading System modules from disk (via file:// urls) or the network, with included caching that respects the Content-Type header.
  • Import Maps (via the applyImportMap api).
  • Tracing hooks and registry deletion API for reloading workflows.
  • Loading global modules with the included global loading extra.

Loading CommonJS modules is not currently supported in this loader and likely won't be. If you find you need them it is more advisable to use Node.js native module support where possible instead of the SystemJS Node.js loader.

Extras

The following pluggable extras can be dropped in with either the s.js or system.js loader:

  • AMD loading support (through Window.define which is created).
  • Named register supports System.register('name', ...) named bundles which can then be imported as System.import('name') (as well as AMD named define support)
  • Dynamic import maps support. This is currently a potential new standard feature.

The following extras are included in system.js loader by default, and can be added to the s.js loader for a smaller tailored footprint:

  • Global loading support for loading global scripts and detecting the defined global as the default export. Useful for loading common library scripts from CDN like System.import('//unpkg.com/lodash').
  • Module Types .css, .wasm, .json module type loading support in line with the existing modules specifications.

Since all loader features are hookable, custom extensions can be easily made following the same approach as the bundled extras. See the hooks documentation for more information.

SystemJS Babel

To support easy loading of TypeScript or ES modules in development SystemJS workflows, see the SystemJS Babel Extension.

SystemJS does not support direct integration with the native ES module browser loader because there is no way to share dependencies between the module systems. For extending the functionality of the native module loader in browsers, see ES module Shims, which like SystemJS, provides workflows for import maps and other modules features, but on top of base-level modules support in browsers, which it does using a fast Wasm-based source rewriting to remap module specifiers.

Performance

SystemJS is designed for production modules performance roughly only around a factor of 1.5 times the speed of native ES modules, as seen in the following performance benchmark, which was run by loading 426 javascript modules (all of @babel/core) on a Macbook pro with fast wifi internet connection. Each test was the average of five page loads in Chrome 80.

Tool Uncached Cached
Native modules 1668ms 49ms
SystemJS 2334ms 81ms

Getting Started

Introduction video.

The systemjs-examples repo contains a variety of examples demonstrating how to use SystemJS.

Installation

npm install systemjs

Documentation

Example Usage

Loading a System.register module

You can load System.register modules with a script element in your HTML:

<script src="system.js"></script>
<script type="systemjs-module" src="/js/main.js"></script>
<script type="systemjs-module" src="import:name-of-module"></script>

Loading with System.import

You can also dynamically load modules at any time with System.import():

System.import('/js/main.js');

where main.js is a module available in the System.register module format.

Bundling workflow

For an example of a bundling workflow, see the Rollup Code Splitting starter project - https://github.com/rollup/rollup-starter-code-splitting.

Note that when building System modules you typically want to ensure anonymous System.register statements like:

System.register([], function () { ... });

are emitted, as these can be loaded in a way that behaves the same as normal ES modules, and not named register statements like:

System.register('name', [], function () { ... });

While these can be supported with the named register extension, this approach is typically not recommended for modern modules workflows.

Import Maps

Say main.js depends on loading 'lodash', then we can define an import map:

<script src="system.js"></script>
<script type="systemjs-importmap">
{
  "imports": {
    "lodash": "https://unpkg.com/[email protected]/lodash.js"
  }
}
</script>
<!-- Alternatively:
<script type="systemjs-importmap" src="path/to/map.json" crossorigin="anonymous"></script>
-->
<script type="systemjs-module" src="/js/main.js"></script>

IE11 Support

IE11 continues to be fully supported, provided the relevant polyfills are available.

The main required polyfill is a Promise polyfill. If using import maps a fetch polyfill is also needed.

Both of these can be loaded conditionally using for example using Bluebird Promises and the GitHub Fetch Polyfill over Unpkg:

<script>
  if (typeof Promise === 'undefined')
    document.write('<script src="https://unpkg.com/[email protected]/js/browser/bluebird.core.min.js"><\/script>');
  if (typeof fetch === 'undefined')
    document.write('<script src="https://unpkg.com/[email protected]/dist/fetch.umd.js"><\/script>');
</script>

located before the SystemJS script itself. The above will ensure these polyfills are only fetched for older browsers without Promise and fetch support.

Note on Import Maps Support in IE11

When using external import maps (those with src="" attributes), there is an IE11-specific workaround that might need to be used. Browsers should not make a network request when they see <script type="systemjs-importmap" src="/importmap.json"></script> during parsing of the initial HTML page. However, IE11 does so. Codesandbox demonstration

Normally this is not an issue, as SystemJS will make an additional request via fetch/xhr for the import map. However, a problem can occur when the file is cached after the first request, since the first request caused by IE11 does not send the Origin request header by default. If the request requires CORS, the lack of an Origin request header causes many web servers (including AWS Cloudfront) to omit the response CORS headers. This can result in the resource being cached without CORS headers, which causes the later SystemJS fetch() to fail because of CORS checks.

This can be worked around by adding crossorigin="anonymous" as an attribute to the <script type="systemjs-importmap"> script.

Community Projects

A list of projects that use or work with SystemJS in providing modular browser workflows. Post a PR.

  • beyondjs.com -TypeScript first meta-framework for universal microfrontends/micronservices.
  • esm-bundle - list of System.register versions for major libraries, including documentation on how to create a System.register bundle for any npm package.
  • es-dev-server - A web server for developing without a build step.
  • import map overrides - Dynamically inject an import map stored in local storage so that you can override the URL for any module. Can be useful for running development modules on localhost against the server.
  • js-env - Collection of development tools providing a unified workflow to write JavaScript for the web, node.js or both at the same time.
  • jspm.org - Package manager for native modules, using SystemJS for backwards compatibility.
  • single-spa - JavaScript framework for front-end microservices.
  • systemjs-webpack-interop - npm lib for setting webpack public path and creating webpack configs that work well with SystemJS.
  • @wener/system - hooks to make System works with npm registry & package.json}

Compatibility with Webpack

Code-splitting builds on top of native ES modules, like Rollup offers, are an alternative to the Webpack-style chunking approach - offering a way to utilize the native module loader for loading shared and dynamic chunks instead of using a custom registry and loader as Webpack bundles include. Scope-level optimizations can be performed on ES modules when they are combined, while ensuring no duplicate code is loaded through dynamic loading and code-sharing in the module registry, using the features of the native module loader and its dynamic runtime nature.

systemjs-webpack-interop is a community-maintained npm library that might help you get webpack and systemjs working well together.

As of [email protected], it is now possible to compile webpack bundles to System.register format, by modifying your webpack config:

{
  output: {
    libraryTarget: 'system', 
  }
}

If using webpack@<5, the following config is needed to avoid rewriting references to the global System variable:

{
  module: {
    rules: [
      { parser: { system: false } }
    ]
  }
}

Using npm packages

Third party libraries and npm packages may be used as long as they are published in a supported module format. For packages that do not exist in a supported module format, here is a list of github repos that publish System.register versions of popular third party libraries (such as react, react-dom, rxjs, etc).

Contributing to SystemJS

Project bug fixes and changes are welcome for discussion, provided the project footprint remains minimal.

Task running is handled by Chomp (https://chompbuild.com).

To run the tests:

npm install -g chomp
chomp test

Changes

For the changelog, see CHANGELOG.md.

License

MIT

plugin-less's People

Contributors

guybedford avatar munawwar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

plugin-less's Issues

Export a compiled CSS as text?

Now I'm not sure how to handle this, but we're using JSPM and SystemJS and we want to get the compiled CSS as text stored in an exported variable. Something like:

import style from './styles.less';

I could fork this plugin and spin up my own variant but I was wondering if I can do it in such a way that I can bring this upstream โ€” that is, if you think it's suitable for it.

JSPM installation doesn't work

Hi!

I have installed it throught jspm: jspm install less
then it fails trying to find lesscss without success, on the browser you can see

Uncaught (in promise) Error: (SystemJS) XHR error (404 Not Found) loading http://localhost:8080/lesscss.js

and trying to build a bundle:

(SystemJS) ENOENT: no such file or directory, open '[path..]/www/lesscss.js'

just looking to plugin-less I have seen:

that the dependeny to lessscss is on less.js:17
return System['import']('lesscss', module.id)

and probably the configuration related to it is on package.json:13-18

    "map": {
      "lesscss": {
        "node": "./less-node.js",
        "browser": "./less-browser.js"
      }
    }

but probably something is missing here :'(, maybe I should add something else... as you inidicate for System.js installation

Thanks a lot!

Can't use less

Hi,

I have created an angular2 project with some less files.
I configured my systemjs.config file as mentionned in the doc, but the scripts seem not to be loaded.

Something is missing, but I can't figure out what.
Any suggestion?

plugin-less instantiates CSSPluginBase() when it is not running in a browser.

I am trying (unsuccessfully) to use plugin-less in conjunction with server-side rendering. The root cause of the problem is CSSPluginBase.prototype.instantiate(), which attempts to inject a style element into the DOM without document being defined:

CSSPluginBase.prototype.instantiate = function(load) {
  if (this.builder)
    return;

  var style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = load.metadata.style;
  document.head.appendChild(style);
};

module.exports = CSSPluginBase;

I am not sure what the correct fix is in this case. There may be two. First, explicitly checking if document is defined in CSSPluginBase.prototype.instantiate() seems appropriate and works for me in practice:

  if (this.builder || typeof document === 'undefined')
    return;

Second, less.js may require a fix so that the CSSPluginBase() constructor is not even called unless plugin-less is running in a browser. plugin-css explicitly checks if it is running in a browser, for example, and does not have an issue with server-side rendering. Neither does mobilexag/plugin-sass.

less-node.js overwrites NODE_ENV

In the following code from less-node.js, the line pEnv.NODE_ENV = productionEnv ? 'production' : 'development'; overwrites the actual environment such that commands like jspm run ... do not behave as expected. If the module being run imports plugin-less at any point, then NODE_ENV will always be 'production'.

$__System.registerDynamic("@system-env", [], false, function() {
  return {
    "production": true,
    "browser": false,
    "node": true,
    "dev": false,
    "default": true
  };
});

$__System.registerDynamic("github:jspm/[email protected]/process-node.js", ["@system-env", "@node/process"], true, function($__require, exports, module) {
  ;
  var define,
      global = this,
      GLOBAL = this;
  var productionEnv = $__require('@system-env').production;
  var process = $__require('@node/process');
  var pEnv = process.env;
  pEnv.NODE_ENV = productionEnv ? 'production' : 'development';
  module.exports = process;
  return module.exports;
});

I discovered this while working through a separate issue with server-side rendering when plugin-less (via css-plugin-base) attempts to inject into the DOM but document is not defined (of course).

Let's have a single less loader plugin

I'm the author of systemjs-less-plugin, which has got quite some traction, zero dependencies, and has just got a the feature of updating its bundle of npm:less both for node and browser.

What do you think if I transfer that repo to this organization so we provide one canonical less loader plugin?

Resolve package paths

The only way I could find to reference a package that contains a less file is to use something like @import '../../jspm_packages/github/distros/[email protected]/bootstrap/index.less'. Which is obviously going to easily end up in a maintenance nightmare down the road.

The import statement in the typescript plugin for example properly resolves the package, without any version information attached, unless the paths start with . or ...

Is there a way to specify the paths in a similar fashion with this plugin, e.g. @import 'bootstrap-less/bootstrap/index.less? Thanks.

Big single file source map generated from @imports in browser mode

In browser mode, when using a single example.less file that do some less @imports on its own,
the source map points to a single big "example.less" file which is just the compiled CSS.

It reduces the utility of source maps in a development workflow.
When generating a bundle (with separateCSS: true), the source maps are correct.

(Not sure if it is a problem in this package or in the less dependency?)

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.