Is there a way to use a CommonJS module on a site like plnkr, JSFiddle, or JS Bin?
I'd want to turn it into a global.
This is for easily providing demos without having to use UMD.
I'd find the Github repos and then reference the source files using rawgit.com.
requirebin is a jsbin like enviroment that allows for modules built using browserify, but I am not aware of a way to use an unpublished module
You can use https://www.skypack.dev/, it adjusts any npm package to be used in an ESM-ready environment
For example, if you want to use a library that uses UMD (Universal Module Definition) or CJS (Common JS), you can use skypack and the module will be converted to ESM (ES Modules).
Working case
The canvas-sketch-util/random library uses CJS to import and export some modules (it use require('something') inside), but the code is converted to ESM with that service, and can run directly in the user's browser
<script type="module">
// Use 'https://cdn.skypack.dev/' + 'npm package name' + '#version its optional'
import random from 'https://cdn.skypack.dev/canvas-sketch-util#1.10.0/random'
console.log('A random number: ', random.range(1,10))
</script>
Non-working case
The same library doesn't work if we use https://unpkg.com/, as it only distributes what is ready, and the code gives error (at the very beginning of the file there are already some require functions from CJS):
<script type="module">
import random from 'https://unpkg.com/canvas-sketch-util#1.10.0/random'
console.log('A random number: ', random.range(1,10))
</script>
Important
It's important to use type="module" inside the script, jsfiddle and codePen already do that, it can work locally too.
Each library has an export differently, you must understand how the library is being exported to be able to import it into your code. Here are some examples of different ways of importing, not all cases, you have to know which way of import is the right way.
<script type="module">
// Usually when don't have a default export
import * as libOne from 'https://cdn.skypack.dev/lib-one'
libOne.initSomething({someconf:true})
// OR
libOne(someParam1, someParam2)
// Usually when export is just one function/object
import libTwo from 'https://cdn.skypack.dev/lib-two'
libTwo(someParam1, someParam2)
// Usually when there are several things inside the lib and you only want to use one
import { libThree } from 'https://cdn.skypack.dev/lib-three'
libThree(someParam1, someParam2)
</script>
Final considerations - 2022
Their website ( https://www.skypack.dev/ ) says the following
Skypack is free to use for personal and commercial purposes, forever. The basic CDN is production-ready and is backed by Cloudflare, Google Cloud, and AWS. We're fully committed to building a core piece of infrastructure you can rely on.
So it seems to be something you can trust
Related
I'm trying to use lodash in my web application. I have installed lodash using npm in my local project.
I plan on using the ES6 modules in my code.
Here is my main.js file:
import * as _ from "lodash";
_.each([1, 2, 3, 4], (i) => {
console.log('index each ' + i);
});
And I have included it in index.html as:
<script src="js/main.js", type="module"></script>
But I get the following error in the browser console.
Uncaught TypeError: Failed to resolve module specifier "lodash".
Relative references must start with either "/", "./", or "../".
Note: I do not wish to use any bundling tool.
If you don't wish to use any bundling tools, you will need to provide a path to the lodash folder within node_modules, relative to the JavaScript file that you have the import statement in.
If you do not wish to use a bundler, it would also be worthwhile importing from the specific file, the function you need. For example:
import _each from '../node_modules/lodash/each'
As of 2021, please consider the following statement by Márton Salomváry (Jan 2018):
Unfortunately even most libraries authored or published in ES6 module format will not work because they target transpilers and rely on the Node.js ecosystem. Why is that a problem? Using bare module paths like import _ from 'lodash' is currently invalid, browsers don’t know what to do with them.
And also the statement by Jake Archibald (May 2017):
"Bare" import specifiers aren't currently supported.
Valid module specifiers must match one of the following:
A full non-relative URL.
Starts with /.
Starts with ./.
Starts with ../.
And javascript.info:
In the browser, import must get either a relative or absolute URL. Modules without any path are called “bare” modules. Such modules are not allowed in import.
Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have their own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet.
Bundlers facilitate the use of "Bare Imports" which is not supported by the browser yet. Unless you bundle your code, I recommend using the solution proposed by #Asler. Besides, a lot of work is currently being done to study the implementation of "Bare Imports" in the browser, please follow this link if you want to monitor the overall progress.
Eventually you can't use JS modules on browser like that. These modules are for webpack or other bundler.
Try module lodash-es
import each from '../node_modules/lodash-es/each.js'
If you are trying to import css file, make sure to mention .css in import statement.
you can add your node_modules to the public dirs, so you can easily shorten your importing syntax from ../../../../node_modules/my-package into /my-package
also, you need to specify the full path including the file and the extension
import mod from "/my-package/file.mjs"
All major browsers have supported ES6 modules for some time.
These differ from many of the server-side approaches in that they need to specify the exact file to import from - they can't use file discovery.
This makes sense - in Node applications or bundlers like WebPack they only really need the name of the module, and then can spend a bit of extra time discovering the specific file that holds the code. On the web that could be a lot of wasted round trips (is 'library' in library/index.js, or library/library.js, or library.js? require() doesn't care but on the web we have to).
TypeScript has ES6 modules support (set "module": "es6" in tsconfig.json) but it appears to be using a file discovery approach...
Suppose I have library.ts:
export function myFunction(...) { ... }
Then in app.ts:
import {myFunction} from './library';
var x = myFunction(...);
However, this is unchanged when transpiles - the TS output still has the 'library' name for file discovery, which doesn't work. This throws an error because 'library' isn't found:
<script type="module" src="app.js"></script>
In order for ES6 modules to work the TS output needs to reference the specific file:
import {myFunction} from './library.js';
var x = myFunction(...);
How do I make TS output valid ES6 module import statements?
Note: I am not asking how to make a bundler join the TS output into a single file. I specifically want to load these files individually using <script type="module">
This is a bug in TypeScript, though there's some debate about whether it should be fixed.
There is a workaround: while TS won't allow you to specify a .ts file as the source of a module, it will let you specify a .js extension (and then ignore it).
So in app.ts:
import {myFunction} from './library.js';
var x = myFunction(...);
This then outputs correctly in app.js, and TS has found the import definitions and bindings correctly.
This has one advantage/gotcha to be aware/careful of: TS just ignores the .js extension and loads the rest of the path with the usual file discovery. This means that it will import library.ts, but it would also find definition files like library.d.ts or import files in a library/ folder.
That last case might be desirable if you're joining those files together into a library.js output, but to do that you're going to be looking at either lots of nested tsconfig.json files (messy) or possibly the pre-transpiled output of another library.
The compiler takes a module kind flag:
--module ES2015
And you'll also need to be targeting ECMAScript 6 / 2015...
--target ES2015
You need both the module kind and the compilation target to be ECMAScript 2015 minimum to have "zero transformation imports".
Your import statements should look half-way between your two examples:
import {myFunction} from './library';
Additional Notes
There is still clearly a lot of discussion about module resolution... there is the TC39 specification, and the WHATWG specification - plus Node is currently still file-extention-less... looks like RequireJS might live longer than we all thought... please see:
The TypeScript thread for supporting file extensions during import transpilation (i.e. will it add the file extension?).
Recommendation
Stick with a module loader, for example RequireJS or SystemJS. This also means your modules can be shared between browser and server by using UMD or System module kinds repectively.
Obviously, once the ECMAScript discussion reaches a conclusion this will need a revisit.
For a personal project I went the other way. Since I had NPM calling a shell script to copy index.html over to the /build folder, I had the shell script then mass-rename all .js files to have no extension at all.
I did have to inform IIS in "MIME Types" section that an extension-less file should have MIME type application/javascript for that particular site, but it did indeed work. No webpack, no SystemJS, nothing. Index.html just had a hard-coded
<script type="module">
import "./app";
</script>
This was important because I was using a testing framework jest which did not like me putting the .js into the typescript import statements.
I'm trying to use import and export to create modules and it's not working.
I added https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js to the index.html header and tried to import a js file and get an error message saying SyntaxError: import declarations may only appear at top level of a module. What can I possibly be doing wrong?
I know I can use require.js but rather use import and export.
HTML
script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script
JS File
import Mymodule from './modules/mymodule';
Babel cannot perform client-side transpiling of modules, or rather it is not universally supported by browsers. In fact, unless you use a plugin, Babel will transform import into require().
If I run the following code:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
<script defer type="text/babel" data-presets="es2015">
import Mymod from './modules/module';
Mymod();
</script>
</head>
I get the following error:
Uncaught ReferenceError: require is not defined
From Babel Docs:
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side. See setup build systems for more information.
Most people choose a pre-compiled module bundler like Webpack or Rollup.
If you really want to perform this client-side, use RequireJS with Babel run via a plugin, though you may need to use AMD syntax.
Native browser support for ES6 modules is still in early stages. But to my knowledge there isn't a preset/plugin available yet for Babel to tell it not to transform import/export statements.
The scripts that babel-standalone translates execute by default in global scope, so any symbols defined by them are automatically available to every other module. From that perspective, you don't need import/export statements in your modules.
However, you might be trying to maintain source files that can be used both by babel-standalone (e.g. for quick test environments, feature demonstrations, etc) and via bundlers such as webpack. In that case, you need to keep the import and export statements there for compatibility.
One way to make it work is to add extra symbols into the global scope that cause the import and export code that babel generates to have no effect (rather than causing an error as usually occurs). For example, export statements are compiled into code that looks like this:
Object.defineProperty (exports, "__esModule", {
value: true
});
exports.default = MyDefaultExportedClass;
This fails if there is no existing object called "exports". So give it one: I just give it a copy of the window object so anything interesting that gets defined is still accessible:
<script>
// this must run before any babel-compiled modules, so should probably
// be the first script in your page
window.exports = window;
import statements are translated to calls to require(). The result (or properties extracted from it) is assigned to the variable used as the identifier in the import statement. There's a little bit of complication around default imports, which are different depending on whether or not the result of require() contains the property __esModule. If it doesn't, things are easier (but then you can't support having both default and named exports in the same module ... if you need to do this, look at the code babel produces and figure out how to make it work).
So, we need a working version of require(). We can provide one by giving a static translation of module name to exported symbol/symbols. For example, in a demo page for a React component, I have the following implementation:
function require (module) {
if (module === "react") return React;
if (module === "react-dom") return ReactDOM;
}
For a module returning multiple symbols, you'd just return an object containing the symbols as properties.
This way, a statement like
`import React from "react";`
translates to code that is effectively:
`React = React;`
which is roughly what we want.
How can I import a static url using webpack:
index.js
import 'http://google.com/myscript.js'
It's really unclear what you're trying to do, but in general you have a few options.
Pre-download the script or install it via NPM. This probably is the preferred way to deal with external dependencies. Once it is local you can easily import or require it like any other module.
If it absolutely must be loaded dynamically you will need a 3rd party module such as https://www.npmjs.com/package/scriptjs which can easily download 3rd party modules at runtime and block the execution of the rest of the script until it has been parsed.
Use a <script> tag and include it on your page. This only works if it's a general dependency that can be loaded before everything else (maybe for a polyfill or a library you depend on everywhere like jquery.)
I hope that helps!
This webpack issue says you can use this comment to allow the import to just work. Though this is only dynamic import not static.
import(/* webpackIgnore: true */ "https://example.com");
First seen here https://stackoverflow.com/a/69951351/4619267
import is es6. With es5 and webpack, use require, or better wrap your JS files with AMD/UMD.
There are many ways to format JavaScript modules: AMD, CommonJS, UMD, ES6, global script. I've seen projects that structure their source code in whatever way they want and run a build process to generate a dist directory containing code in all the above formats. This has the advantage that the user of the code can just pick whichever format is most applicable to his environment.
This method works fine as long as the module has no dependencies on other modules. In the case where the modules must import other modules, there are implied complications. For example RequireJS uses a config file that looks like:
requirejs.config({
paths: {
'jquery': 'js/lib/jquery',
'ember': 'js/lib/ember',
'handlebars': 'js/lib/handlebars',
'underscore': 'js/lib/underscore'
}
});
Other loaders have equivalent mechanisms for mapping import paths.
If jQuery is a dependency, should the module import it from the path 'jquery'? What if the system in which it is being incorporated stores jQuery at the path 'libs/jquery'? In this case, is it the responsibility of the author of the system incorporating jQuery to provide aliases in the configuration of the import path?
This questioning strongly suggests that a truly reusable module must provide code formatted in all module formats as well as document clearly upon what libraries (and versions thereof) it depends and document what import paths at which those libraries are assumed to exist.
For example I could author a fancy jQuery plugin that I distribute in AMD, CommonJS, ES6, and global variations. I would document that this plugin depends on jQuery version 2.0 imported through the path 'jquery_on_a_path_that_confuses_you'. The would-be user of this plugin must copy the plugin into his project and then configure his module loader or build tool to export jQuery at the path 'jquery_on_a_path_that_confuses_you'.
As far as I can tell:
There is no standard for what to use for import paths.
There is no standard way to express the dependency, version, and import path requirements to the user of a piece of code.
There is no standard remedy to deal with clashing import paths or load multiple versions of a library.
Does there exist any plan to deal with this strange arrangement? To me it seems a little crazy to have module systems that don't know how to name their modules. Am I wrong?
You may want to check jspm.io + SystemJS which is a relatively new package manager and universal module loader which is increasing in popularity.
Please find below some presentations and article on the subject I found useful:
https://www.youtube.com/watch?v=MXzQP38mdnE,
https://vimeo.com/65042246,
https://www.youtube.com/watch?v=szJjsduHBQQ,
http://javascriptplayground.com/blog/2014/11/js-modules-jspm-systemjs/
Late with the answer, but if you're after writing plain JS code (without jQuery or other frameworks), I've found that there's the deploader.js repo, which you can use to wrap any kind of JS into modules and do dependency loading.
May worth checking out.