I've been using lodash in my applications and libraries and I've been packaging my applications and libraries with webpack (and UglifyJS).
The problem with this is that when minifying, if you imported lodash in its entirety, UglifyJS doesn't know to remove the functions from lodash that are unused. Clever people have come up with importing just the functions you're going to use from lodash, like so:
var forEach = require('lodash/array/forEach');
This works great and results in a much smaller compiled version of my code. However, it can be very tedious in files that use many parts of lodash.
Can the same effect be achieved using ES6-style imports and Babel's DCE transformer? For example:
import { forEach } from 'lodash';
I'm suspicious since it's importing from the the root of the lodash library and not from the individual function's file like the former example.
Given you are likely using Babel already, I think babel-plugin-lodash can do the trick. It is able to perform transformation from
import lodash from 'lodash';
lodash.map([1, 2, 3], function(x) {
// ...
});
to
import _map from 'lodash/collection/map';
_map([1, 2, 3], function(x) {
// ...
});
IMPORTANT! As mentioned by #reflog at comments, this approach doesn't work with lodash chaining!
Related
I do my development using modern JS (ES6) which means modules.
Although Three.js is available as an ES6 module. The line library - LineSegmentsGeometry, LineGeometry, LineSegments2, etc. - is not.
What are my options here?
You have a couple options.
First and foremost, edit the code.
You're welcome to modify the code, and so you could manually turn it into an ES6 module. You would want to remove any references of THREE, and export anything that was normally attached to that object. You'll also need to import any required core THREE.js components, like Mesh, Vector3, etc.
The way I prefer to do this is to copy the file I'm updating locally, and change references to it. For example:
// local_three_modules/LineSegments2.js
import { Mesh, Vector3, etc. } from "three"
let LineSegments2 = function ( geometry, material ) {
// ...
}
export default LineSegments2
// app.js
import { Mesh, Vector3, etc. } from "three"
import LineSegments2 from "./local_three_overrides/LineSegments2.js"
// and so on...
Your other option is to use a bundler with an export loader.
Webpack (and other bundlers, I'm just more familiar with Webpack) provides a exports-loader which can be used against specific files that don't export anything. For example, you can tell the exports-loader to export THREE from LineSegments2.js. To get webpack involved in this process, you need to tell it to use the loader on the file. You can do this through the webpack configuration, or inline in the code like this:
import THREE from "exports-loader?THREE!./node_modules/three/examples/js/lines/LineSegments2.js"
Previously I've been using following in my JS entry points:
require('coffeescript/register');
module.exports = require('./entry.coffee');
What is the corresponding ES6 syntax of this?
Following does not seem to register anyhing.
import 'coffeescript/register';
export * from 'entry.coffee';
Error is:
Cannot find module 'entry.coffee'
Tested on Coffeescript 2.0 beta2.
Update:
Changing path to relative:
import 'coffeescript/register';
export * from './entry.coffee';
finds the entry.coffee, but treats it as JS. Hence, Coffeescript is not handled by transpiler.
You don't need to use coffeescript/register if you're transpiling the CoffeeScript as part of your bundling process (which you need to, if you're using Rollup) — that's just a way to enable Node to run CoffeeScript files without having to first convert them.
Instead, try adding rollup-plugin-coffee-script to your rollup.config.js file.
I am trying to test lodash, and apparently the following line won't work in the REPL:
import curry from 'lodash/curry';
See, e.g., babel-node es6 "Modules aren't supported in the REPL"
Why does babel-node not support module loading in the REPL?
Is there a way that I can pre-load a module like lodash into babel-node? (e.g. via a command line option or a configuration file)
If not, is there another way of evaluating ES6 with lodash preloaded?
So far, I've tried the online REPL at https://babeljs.io/repl/, and evaluation in the Console in Firefox. None worked.
import surely won't work, because the package should be installed first and bundled in order to be imported, which isn't the duty of Babel REPL.
Lodash is already loaded and used in Babel REPL, it can be used in REPL as _ global:
const { curry } = _;
If the question isn't limited to Lodash, the quickest way to get third-party library in REPL is to load the script manually. And since Babel website has jQuery loaded (as almost any website), the shortest way to do this is jQuery.getScript, in console:
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js');
After that Lodash _ global becomes available in REPL.
The whole code can be wrapped with callback to skip console part:
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js', () => {
console.log(_.VERSION);
});
babel-node REPL doesn't support imports, as the links in the original post say. Instead, require should be used, like anywhere else in Node.
var { curry } = require('lodash')
This requires to have lodash installed in node_modules that exists in current working directory.
I am currently learning Meteor and I found out something that intrigued me.
I can load HTML and CSS assets from a JS file using the import statement.
import '../imports/hello/myapp.html';
import '../imports/hello/myapp.css';
import * as myApp from '../imports/hello/myapp.js';
This was a surprise to me so I ran to google but could not find this behavior documented in the specification for ES6 import or in Meteor's Docs.
So my questions are:
Can I rely on this behavior to build my apps?
Will my app will break when Meteor gets around to fix it -- if it's a bug --?
Notes
I am using Meteor v1.3, not sure if this works also with previous versions.
You can download the app to see this behavior from Github
After going through the implementation of the built files for my app
I found out why this works.
HTML
Files are read from the file system and their contents added to the global Template object, e.g.,
== myapp.html ==
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
results in the following JS code:
Template.body.addContent((function () {
var view = this;
return [
HTML.Raw("<h1>Welcome to Meteor!</h1>\n\n "),
Spacebars.include(view.lookupTemplate("hello"))
];
}));
Which is wrapped in a function with the name of the file as it's key:
"myapp.html": function (require, exports, module) {
Template.body.addContent((function () {
var view = this;
return [
HTML.Raw("<h1>Welcome to Meteor!</h1>\n\n "),
Spacebars.include(view.lookupTemplate("hello"))];
}));
Meteor.startup(Template.body.renderToDocument);
Template.__checkName("hello");
Template["hello"] = new Template("Template.hello", (
function () {
var view = this;
return [
HTML.Raw("<button>Click Me</button>\n "),
HTML.P("You've pressed the button ",
Blaze.View("lookup:counter",
function () {
return Spacebars.mustache(view.lookup("counter"));
}), " times.")
];
}));
},
So all of our HTML is now pure JS code which will be included by using require like any other module.
CSS
The files are also read from the file system and their contents are embedded also in JS functions, e.g.
== myapp.css ==
/* CSS declarations go here */
body {
background-color: lightblue;
}
Gets transformed into:
"myapp.css": ["meteor/modules", function (require, exports, module) {
module.exports = require("meteor/modules").addStyles("/* CSS declarations go here */\n\nbody {\n background-color: lightblue;\n}\n");
}]
So all of our CSS is also now a JS module that's again imported later on by using require.
Conclusion
All files are in one way or another converted to JS modules that follow similar rules for inclusion as AMD/CommonJS modules.
They will be included/bundled if another module refers to them. And since all of them are transformed to JS code
there's no magic behind the deceitful syntax:
import '../imports/hello/myapp.html';
import '../imports/hello/myapp.css';
They both are transpiled to their equivalent forms with require once the assets have been transformed to JS modules.
Whereas the approach of placing static assets in the imports directory is not mentioned in the official documentation,
this way of importing static assets works.
This seems to be at the core of how Meteor works so I'd bet this functionality is going to be there for a long while.
I don't know if to call this a feature maybe a more appropriate description is unexpected consequence but that would
only be true from the user's perspective, I assume the people who wrote the code understood this would happen and perhaps even
designed it purposely this way.
One of the features in Meteor 1.3 is lazy-loading where you place your files in the /imports folder and will not be evaluated eagerly.
Quote from Meteor Guide:
To fully use the module system and ensure that our code only runs when
we ask it to, we recommend that all of your application code should be
placed inside the imports/ directory. This means that the Meteor build
system will only bundle and include that file if it is referenced from
another file using an import.
So you can lazy load your css files by importing them from the /imports folder. I would say it's a feature.
ES6 export and import functionally are available in Meteor 1.3. You should not be importing HTML and CSS files if you are using Blaze, the current default templating enginge. The import/export functionality is there, but you may be using the wrong approach for building your views.
Some old Javascript libraries directly attach an object to the global scope (no AMD, no UMD, no commonJS).
Is there a nice way to "include" a global module in ECMAScript 6 code?
I'm just aware of the following line:
import './globallib.js';
And then access the global variable directly.
Example: to load QUnit test function:
import 'qunit';
test('my test', function () {
ok(true, 'QUnit loaded');
});
Is this the right way?
PS. I encountered this problem while working with QUnit 1.8 in a project that compiles to ES 5 using Babel and Browserify. In QUnit 2 they're gonna avoid globals. But I have this question in general.
As far the QUnit exports its methods into window (according source code), you right, import expression is enough.
But anyway, you can't use raw imports in browsers, so you have to use some preprocessing. Webpack and browserify will work for you, but it would not be so for another build systems.