With the use of transpilers it is already possible to use ES6 modules. One of the easiest ways is using Browserify and Babelify.
The problem I'm having is how to handle dependency management.
In the old days you'd just have some Bower dependencies. The build would bundle non-CDN to vendor.js and project specific files to foobar.js (or whatever).
So then you'd be able to use the resulting code in a different project by simply bower install foobar --save.
If both foobar and your new project had a common dependency it would be easily resolved with Bowers flat dependency.
Now in come ES6 modules:
Say I have a project foo using lodash. The directory structure is as follows:
src/js/foo.js
src/vendor/lodash/dist/lodash.min.js
And foo.js starts by declaring:
import * as _ from '../../vendor/lodash/dist/lodash.min.js';
or (as Browserify wants since Babelify transpiles to CommonJS):
import * as _ from './../../vendor/lodash/dist/lodash.min.js';
If I now round up and publish my foo project and start a new project bar that uses foo this will be my directory structure.
src/js/bar.js
src/vendor/foo/dist/foo.js
src/vendor/lodash/dist/lodash.min.js
But that would not work since the path from foo to lodash is now broken (if I understand Browserify correctly the dot-slash in './blaat/file.js' is relative to the file it's being called from).
Is some way to import without making any file path assumptions?
Isn't there some way to indicate multiple source roots? (ie in the above case src/js and src/vendor ... well, ideally you'd just want to state import * as _ from 'lodash';)
I've only used Browserify with Babelify on cli. Should I be using some other transpiler?
I think that jspm is the solution your looking for. It will help you out without making file path assumptions when importing modules. It uses the SystemJS dynamic ES6 loader. Watch the video that is posted on their site for a very good explanation on how it all works, Guy Bedford: Package Management for ES6 Modules [JSConf2014].
Related
I have a library (ES6) which is composed on many sub-modules, say
- package.json
- lib
- my_package
- file1.js
- file2.js
- sub_module1
- file3.js
- file4.js
I currently do imports like this (all inside my package - using file resolution to find, not node_modules resolution):
import {func1} from 'lib/my_package/file1'
import {func3} 'lib/my_package/sub_module1/file3'
So, in practice I have many files across sub-directories.
I am now trying to package and publish my library, which will be installed under node_modules.
It seems to me that the node resolution algorithm (when behind node_modules) only allows for a single entry point (and there is nothing rollup can do about that)
I would like to be able to include many sub directories and files and for them to be resolved individually.
As far as I understand I have to include a single toplevel file that has all the export from machinery. I can only import that single top level file.
This means having to manually create that file. It also means losing the all the sub-module name structuring that comes from the directory structure.
I was wondering: is there any way one can import any other file from a node_module directly?
Node's resolution algorithm only resolves the first part of a module source, so if someone does this...
var foo = require('your-library/subdir/foo.js');
...then Node (or Browserify/Webpack/rollup-plugin-node-resolve) will correctly resolve that to
/path/to/project/node_modules/your-library/subdir/foo.js
The tricky part is that you want to author JavaScript modules, but if someone is using your library in Node then they need CommonJS modules. Rollup can't help you here — you would need to do a one-to-one ESM->CJS conversion for each module. So that means either using Babel, or authoring CommonJS modules in the first place.
I'm trying to build a react application using rollup instead of browserify and babel. I realize I need to use the rollup-plugin-babel to transpile jsx, but when I tell rollup the format is iife, the final page loads with an error:
Uncaught ReferenceError: React is not defined
What do I need to add to the rollup.config.js to include the node modules I've installed in package.json in my final build?
Two options:
Include React as a separate <script> tag before your app bundle
Include rollup-plugin-node-resolve in your config file, to pull in dependencies from your node_modules folder.
If you take the second route you'll also need rollup-plugin-commonjs (to convert the CommonJS module into an ES module). I think you would also need to add import * as React from 'react' to each module that contained JSX, otherwise you'll continue to get the ReferenceError.
Note: you might be able to use rollup-plugin-buble to transpile JSX. It's similar to the Babel plugin but much faster (though it doesn't transpile every ES2015 feature)
Let's say I have an ES6 library "foo" under my /vendor directory in an EmberJS project constructed using the latest ember-cli (at the time of this writing 2.4.3). Assume that foo is a library with multiple files, e.g. bar.js, baz.js, etc. and they all export something.
I would like to take vendor/foo/bar.js, vendor/foo/baz.js, etc. and bundle them into a distribution file, e.g. vendor/foo/dist/foo-bundle.js that I can then import into Ember with:
app.import("vendor/foo/dist/foo-bundle.js");
This appears like it should be possible with a bundler and/or transpiler (like Babel), but it isn't clear to me what tools I should use and in what combination. Does Ember have a built in tool for doing what I want through ember-cli (if it does, I must be blind)? Should I be using an external bundler like webpack, browserify, or rollup?
In general there seems to be a lot of noise around JavaScript tooling making it difficult for me to understand what choices I have for this problem and how to properly leverage them. Any assistance would be greatly appreciated.
Some notes that may be helpful...
I have tried a few things, so far:
I have tried just importing the main.js file, in hopes that EmberJS would also walk the dependency tree and import any other files that were referenced in import statements. This only imported the main.js file and no other dependencies.
I've looked at broccoli-es6modules and had errors when running it, but it also uses esperanto which is deprecated in favor of rollup.
I've also tried using rollup directly, with a minor degree of success, but often times my bundle.js output is empty and doesn't include the code from bar.js or baz.js because I've only imported them in the entry point (e.g. main.js):
main.js
-------
import bar from './bar.js';
import baz from './baz.js';
bar.js
------
export default function bar() {
...
}
baz.js
------
export default function baz() {
...
}
I have found if my main.js includes a function that calls either code from bar or baz I get more than an empty bundle, but if foo is just a collection of scripts from a third-party vendor that have no "application entry point", aside from what amounts to something like a manifest file, rollup seems to be the wrong choice for what I'm looking for.
Thanks again!
(Updated with the latest options.)
There are a few options.
If baz.js and bar.js are your own modules and code, the best if you just place them in app/my-awesome-module folder. You can use ES6 import to import in other place, where you would like to use them. Ember CLI will transpile, concatenate and minify them automatically.
If you would like to use 3rd party modules or solutions, check out http://emberobserver.com, most of the popular library already converted to Ember Addon, so you can install them with ember install.
Use ember-auto-import in your project and import libraries as normal ES6 module like this: import MyCoolModule from "my-cool-module";
I am building a bundle using the SystemJS builder that I'd like to include in another project. The problem I'm running into is that bundle A and bundle B might both contain a 'main' module, and when I bundle them and include them in another project, they collide and everything breaks.
Does SystemJS builder have a better way of namespacing? Or from preventing bundled modules from being exported at all? Or is there another tool I should be using?
SystemJS does not have an easy way to do what you want.
You could import the module by path instead of by name.
import x1 from "folder1/x.js"
import x2 from "folder2/x.js"
You could also try to have two instances of SystemJS.
https://stackoverflow.com/a/30954312/6101582
https://github.com/systemjs/systemjs/issues/982
You could also rename the modules.
So I know how to require and export modules in ES6. But for frameworks like Aurelia, the docs say that you require aurelia like so:
import {LogManager} from 'aurelia-framework';
Do I have to place a JS file named aurelia-framework in the folder where the JS file I'm executing it from resides, or does the import function work similiar to the require function in NodeJS/CommonJS?
According to this article ES6 modules spec only deals with loading modules that are present in the file path. Downloading these files (via NPM or by other means) is outside of scope of ECMAScript 6 modules spec. Nothing is said in the spec about supporting npm package includes (traversing the directory structure down to the /, one directory at a time, looking for a package.json file and then searching within the node_modules directory where package.json file is found). So while the import syntax is similar to commonJS style, the whole magic of looking for modules in the node_modules directory is not included.
So for your example to work, aurelia-framework must be a javascript file somewhere in your file system and it should contain an exports statement.
import {LogManager} from 'aurelia-framework'; // ./aurelia-framework.js
import {LogManager} from '../libs/aurelia-framework'; // ../libs/aurelia-framework.js
with Aurelia, you can install dependent libraries using jspm. you can see an example of that here. jspm will get the packages for you and bring them into subfolders in your project. jspm uses an index (stored in config.js) to know where to locate the files (similar to how requirejs, but works for amd, commonjs, and es6 modules).
there is also an example of using the aurelia libraries with requirejs amd loader. this example uses a bundle of aurelia libraries generated by r.js as shown here