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

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.

Related

How to configure i18n.config.js so that `preact build --prerenderUrls ./prerender-urls.js` succeeds?

I have a frontend project setup with preact-cli, which leverages i18next with http-backend. This configuration is to facilitate the serving of the translations on demand from the CDN the app is to run in production on. So far I can get this to work by doing:
npx preact build --no-prerender
followed with a deploy to AWS Cloudfront
Now I would like to statically prerender some of the major routes, but regretfully, a naive: preact build --prerenderUrls ./prerender-urls.js does not work. The reason for this is that once it is to do the step of prerender-ing those routes, it is trying to leverage the i18next-http-backend in the absence of an http server running. At this point, preact build just keeps on hanging(as if I am doing a preact build --analyze).
As such, for that step, I need to use the i18next-fs-backend instead. Regretfully, while this will work for bundling in the translations on a CI/CD-server for those prerendered routes, it will not work for the translations that need to be served over the http-backend.
I only see two types of solutions to this problem:
Do the build in two steps. First with --no-prerender with an i18n.config.js that leverages the http-backend and then with --prerender with an i18n.config.js that leverages the fs-backend. The problem here is that the hashes are different between the two builds so I can not simply copy over the prerendered routes with the other build.
Setup an http server during the build that can serve those translations. This is possible in itself, but a rather brittle work-around.
There is the concept of a chained-backend with i18next that would allow me to define a fallback, but in the context of a browser, how does it make sense to have i18next-fs-backend as the primary source?
What would greatly help me at this stage is if someone can point out that
Either there is a third viable option that I failed to consider
Either I misunderstood some way of doing chained-backend
Either a confirmation that I am correct and that a strong case can be made that preact-cli needs to allow us to do the build in two parts.

Reduce code size of my Express application

I've been using the Serverless framework to deploy my Express application. I used their Express starter template but since I've added code, when I try to deploy it says: Your code size must be less than 200MB. Try using Webpack, Parcel, or AWS Lambda layers to reduce your code size.
I've looked everywhere for a way to use Webpack to reduce my code size but have had no luck.
How can I use Webpack to make my code smaller than 200MB? Again, outside of more endpoints, my code is identical to this: https://github.com/serverless-components/express/tree/master/templates/express-starter
There are some options possible.
check if whats needs to be ignored(PACKAGES) is really ignored.
maybe you installed some packages that are taking too much space.
that's the main reasons for something like that.
Let me add also some points.
as #Ethanolle pointed - clean up your npm dependencies.
Include only used dependencies in your lambda build.
Take advantage of using npm devDependencies.
Consider using the webpack for creating your bundle - serverless-webpack plugin
As an alternative for webpack you may get the benefit of using the more precise configuration of Serverless how to manage what to exclude/include in a bundle

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'].

Angular2, Loading modules with less server calls

'import {ComponentHere} from "angular2"', this one hits the server with so may calls for getting all the required file. Is there any way to decrease the number of calls to server?
//localhost:9739/node_modules/#angular/common/src/directives/core_directives.js.
//localhost:9739/node_modules/#angular/common/src/pipes/uppercase_pipe.js".
//localhost:9739/node_modules/#angular/common/src/forms/directives/control_container.js".
etc..
Consider using a WebPack (https://angular.io/docs/ts/latest/guide/webpack.html) it normally will decreased the number of files sended to client (but they will be obviously bigger)
You can use "SystemJS Builder" (https://github.com/systemjs/builder) and integrate it into something like Gulp to make it part of your build process for bundles. You give it an entry point (your app) and it then looks at your dependency tree to build your bundle(s).
When your bundle is used, systemjs will import from your bundle instead of every little js file. When I tested with angular2, I had over 700 files downloaded in DEV and only 35 in PROD when using the bundle.

Is it possible to use Dojo build without modifying JS files?

Is it possible to use Dojo build without the need to modify JavaScript files?
The article dgrid and Dojo Nano Build provides the instruction to create the build, but it requires adding the following line into JavaScript file, which initializes the application:
require(['dgrid/dgrid'], function () {
(replacing 'dgrid/dgrid' with your build module name).
However, it is very problematic when using build for own modules, because, of course, in development mode the require with own layer can't be included, otherwise the modifications made to own modules wouldn't be visible. But in production mode this line must be added.
So either you must modify the file manually before production build, or write a script that would modify the file during the build. Both are very error-prone.
Is there a better way to achieve that result? Is it possible for Dojo to recognize that the build is provided and should be used, instead of loading each module separately?
The following line of code can be included in both development and production modes.
require(['dgrid/dgrid'], function () {
I describe the reasons why in my answer here.
What you need to do is configure Dojo differently based on what environment.
In a blog post that I wrote, I describe this in more detail. The following summarizes the post:
I create three modes: Production, Uncompressed, and Development.
Development
When developing code, I will have the js source linked into the web server and the Development mode will point to the dojo.js file and the raw css file(s). The browser will load modules that I need using xhr. And I point to the top level css files which import other css files. The result is that a lot of requests will be made to the server and the loading of the page will be noticeably slow. The benefit is that you can see development changes without having to do a full build.
Production
Production mode points the main dojo file at the dojo.js that is built using the build tool. I also create <script> elements for the other layers that are needed in the page. I point the css to the built css files which the build tool has inlined the imported css. The page loads quickly, but it is difficult to debug
Uncompressed
Similar to production, but I point to the .uncompressed.js files. Production and Uncompressed are available in the released version of our software. I use uncompressed when trying to troubleshoot an issue in a production environment. The value of this mode is dwindling as the developer tools are better supporting compressed javascript (ie source maps, etc.)
Server side
The default mode is Production, but I use a query parameter to switch modes. I also store the current mode in the session, so that I only have to set the mode once to change it. Subsequent pages will run in the changed mode, until I change it back.
Here is a java implementation of this code.