Tree Shaking Lodash with Webpack 3.8.1 - lodash

Lodash#4.17.4
Webpack#3.8.1
babel#7
babel-plugin-lodash#3.3.2
I use named imports when it comes to Lodash. I've configured
#babel/preset-env with 'modules' set to false to prevent transpilation to
Common JS and
use 'lodash' as a plugin in the 'babel-loader' config.
Despite all this, I realised my chunk has the entire Lodash, and is
significantly bloating it up. What can I do to enable lodash from getting
pruned? I am neither importing the entire library in my code , nor am I
using chaining.

I maintain a library of (much) smaller versions of lodash functions. It is written using a modern build chain, so tree shaking should happen easily. You could check whether it has everything you need: micro-dash.

Related

SailsJS Include node_module in view

I'm using sails(http://sailsjs.com) to develop a little platform. Everything goes smoothly following the documentation. But being new to this javascript frameworks world and npm etc etc, i've been having a trouble including other node_modules and use them in the .ejs views...
I understand not all modules are to be included in the views but how can I manage to include some?
Trying to use https://www.npmjs.com/package/vue-slider-component
Thank you in advance and sorry if this error is just plain out stupid.
Your confusion is understandable. The issue is that, until relatively recently, things installed in node_modules were solely for use in the back end code; that is, your Sails.js controller actions, models, etc. After all, the node_modules folder has the word "Node" right in it, and it was created for use with NPM (the Node Package Manager) to help organize Node (i.e. server-side JavaScript) files!
While many front-end plugins were (and still are) published on Bower, newer frameworks like Angular 2 and Vue often publish their plugins to NPM because it reduces the number of moving parts for your app. The problem is, if you try to require('vue-slider-component') in your server-rendered .ejs view, the server (i.e. Sails.js) will try and load and run that code before it renders the view, where what you really want is for that plugin to run in the browser.
The long-term solution is to use something like Browserify or Webpack to compile all of your front-end JavaScript files into a "bundle". So for example if you have a file like assets/js/my-vue-app.js that includes the line:
import vueSlider from 'vue-slider-component/src/vue2-slider.vue'
then Browserify will see that line, load up that vue2-slider.vue file, add it to the top of the my-vue-app.js file, perform some other magic, combine it with your other front-end .js files and output a file like browserified.js which you would then include via <script src="/path/to/browserified.js"> in your HTML.
Since new Sails apps use Grunt to organize and inject those <script> tags into your views for you, it can be kinda confusing as to how you would get something like Browserify or Webpack to work with Sails. For Sails 1.0, there's a seed project for using Webpack instead of Grunt. For Sails v0.12.x, you'll have to Google around to find some examples of using Broswerify or Webpack with Sails.
A short-term solution, and probably not as maintainable in the long run, is to save the contents of the minified vue-js-slider component into your assets folder (e.g. as assets/js/vue-slider-component.js), add it to your HTML with <script src="/js/vue-slider-component.js"> and access it in your code as window['vue-slider-component'].

HTTP/2: how do I load npm modules in the browser without bundling?

I use Browserify at the moment to bundle my client-side modules into bundles. Each bundle is then loaded as a script tag.
However with HTTP/2, my understanding is that bundling and minification are no longer best practices due to the amount of simultaneous connections available between the client and the server.
So how do I load npm modules in the browser without bundling?
I guess I want to be able to do
var someModule = require('some-module');
And have 'some-module' fetched from the server dynamically.
(I am aware there may be adverse affects on older HTTP/1.1 clients.)
You can't (without hacks and/or rewriting the files), because CJS require is sync. Even if you could, it would still be slow.
JS thread needs to be suspended waiting for the dependency to be loaded and executed. Without modifying source files doing this would require hacks like sync XHR or document.write, but these won't be able to load dependencies in parallel.
You could theoretically use some tool to rewrite the files to convert imperative require to callback-driven one (sort-of like conversion of CJS to AMD or ES6 yield compilers for ES5), but that would probably defeat your goal of using npm modules as-is.
And finally, even if you could load them (or used ES6 modules and travel a bit to the future), it would still be slower than bundling, because the browser doesn't know the full dependency tree, so it has to wait to discover dependencies of dependencies.
I do recommend webpack chunking (use the analyzer to find chunkable parts of the app) if you'd like to load your app in smaller pieces. It requires using an async require.ensure(cb) though.
Depending on what you're using to build your JS into a useful browser bundle, the tools will vary.
If you're using webpack, they have a built in feature for lazy loading:
https://github.com/webpack/bundle-loader
If you're using browserify, there is a module called externalize that aims to do this:
https://github.com/epeli/browserify-externalize
If you're using something else, I'd recommend searching for that builder's name and "lazy loading". I know RequireJS has supported this for a long time, too.

Simple Babel transpiled es6 Module Loading

I'm looking for simple module loading for import/export es6 modules transpiled by babel.
Start with es6 source files with import/export modules for use in the browser
Statically transpile this to es5 with babel, with a config specifying whichever module transform (amd, commonjs, systemjs) is simplest to load.
Do not use npm for the modules, nor any other complex workflow. Just babel transpiled files.
Load these es5 files with modules, with a <script> to load a library that the babel transpilation used for loading es6 modules.
I'd like to avoid browserify, webpack, jspm etc. Just simple transpiled es6->es5 and using the library babel compiled modules to. I don't need bundling. We're talking simple, basic javascript here.
Is this possible? If so, how?!
All the module loading discussions I've seen use complex workflows that seem to me to be unnecessary. I'd like to simply use es6 import/export in a set of files and use them as simply as possible in the browser.
Guy Bedford answered this in the SystemJS Google Group:
https://groups.google.com/forum/?hl=en#!topic/systemjs/a7vB2YmdXp8
Here is a talk I gave on it to my team, the details are at the end:
http://backspaces.net/temp/Modules.pdf
The short version is: configure babel to have babel-plugin-transform-es2015-modules-systemjs, run your modules thru babel with just this transform unless you need more of the es6 features (Chrome is 91% complete), and have your html include:
<script src="system.js"></script>
and
<script>
System.import('lib/main');
</script>
No webpack, npm/browserify, jspm, bundling, ... or any other of the (far too) many module workflows.
It seems like you could use babel-cli to do what you want. Perhaps something like babel src --out-dir lib.

How to blacklist specific node_modules of my package's dependencies in react-native's packager?

I'm putting together a streamlined development process with react and react-native that:
encourages packages,
uses babel to transform es6 to js (it compiles before publishing/installing),
has a playground that let's you play with both native and web components.
The web part of it is perfectly fine. It's the native one that's causing issues and it has to do with react-native's packager.
The bottom line is: if the package is either linked through npm link or required directly from the playground as in require('../../') react-native's dependency resolver will go forever trying to identify dependencies inside my package's node_modules, most times it never finishes doing it.
The temporary solution I've found is to install the package in playground but this involves re-installing it every time I do an update, which isn't great because you can't see your changes right away (even if it would be automated, it would take time).
I believe that a better solution would be to ask the dependency resolver to ignore those specific modules I don't need (those in devDependencies mainly!). I tried mangling react-native/packager/blacklist.js by adding paths to that list and even putting checks against the dependency resolver but none of that would work.
Can someone with more experience with the packager give me a hint as to how I'd go about making the dependency resolver pass? Alternatively, it would be great if the packager could be separated and the transform process left to choice but I don't know if that would be doable either.
I found out the following solution, based on the comment in default.config.js:
* If you need to override any of this functions do so by defining the file
* `rn-cli.config.js` on the root of your project with the functions you need
* to tweak.
Create a rn-cli.config.js in the root of your project with the following contents:
var blacklist = require('react-native/packager/blacklist');
var config = {
getBlacklistRE(platform) {
return blacklist([
/node_modules\/my-package\/excluded-dir\/.*/
]);
}
};
module.exports = config;
The second argument to the blacklist function is an additional list of blacklisted paths, which can be regular expressions. See react-native/packager/blacklist.js for more examples.

Shimming dependencies of dependencies with browserify-shim

I'm trying to refactor a library that uses Browserify by shimming certain modules out of the bundle using browserify-shim. Specifically, the library uses require("codemirror") but I want to provide a bundle that doesn't include CodeMirror but will rather use one that is provided via CDN.
So I've got browserify-shim config in my package.json like
"browserify-shim": {
"jquery": "global:jQuery",
"codemirror": "global:CodeMirror"
}
So far so good. require('jquery') and require('codemirror') have disappeared from the browserified bundle and been replaced by the expected code snippet to grab jQuery and CodeMirror off of the window object.
The library also requires some CodeMirror add-ons. For example require('codemirror/addon/hint/show-hint.js'). That's fine. I want that add-on bundled. However, within this add-on is a UMD wrapper that includes require("../../lib/codemirror"). Browserify is seeing this and is bundling the CodeMirror from /node_modules/codemirror/lib/codemirror.js because of this (I think). I want this to use window.CodeMirror as defined in the codemirror shim instead, but cannot figure it out. Have tried many variations including the following:
"browserify-shim": {
"jquery": "global:jQuery",
"codemirror": "global:CodeMirror",
"../../lib/codemirror": "global:CodeMirror",
"codemirror/addon/hint/show-hint.js": {
"exports":null,
"depends":["../../lib/codemirror:CodeMirror"]
}
}
That require("../../lib/codemirror") will not go away! I'm sure I'm missing something.
I'm running this from a Gulp script, but I don't think that should make any difference. Browserify version 3.38.1. Browserify-shim version 3.7.0.
Any ideas?
If you add browserify-shim with {global: true}, it should be applied to your dependencies' dependencies (and so on) as well, which should hopefully do what you want.
Assuming you're using raw browserify in your Gulpfile, instead of:
b.transform('browserify-shim');
do:
b.transform({global: true}, 'browserify-shim');
If you're using gulp-browserify, I'm not sure whether there's any way to specify global transforms.
{global: true}
works for me... why is this not a default?