When running jshint to validate JS code, I often get errors like
line 264, col 11, 'Cookies' is not defined.
Cookies come from
//= require js.cookie
Which compiled as part of Rails asset pipeline, so JSHint doens't know about it.
Is there a way to set this up so that JSHint runs on a file with all dependencies in place? Or are there any other alternatives?
You can consider using globals option to make jshint aware of shared globals.
If the above proves to be too tedious, then you run jshint after running the files through sprockets - ie. run rake assets:precompile and then run jshint on generated files in public/assets.
But the best course of action I can recommend is something different:
You should consider using a proper module system as opposed to using sprockets for javascript dependency management. This will alleviate the root problem of shared globals (which is a widely regarded poor programming practice).
While the community had come up multiple module systems with varied levels of community acceptance - the best option right now is to embrace the ES6 modules standard. It is good to finally have a standardized approach for modularity. I have recently written a short guide on integrating ES6 modules with rails.
In a nutshell, the ES6 modules standard is a superior option for organizing javascript today as opposed to solutions like AMD, CommonJS or Sprockets directives which were developed in an era when no standardized solution for modular javascript was available.
Related
I've recently gone down the rabbit hole of learning about modular programming with JavaScript, including some history of JS module systems, bundlers and ES2015 Modules. I now understand some of the pains that bundlers help/ed alleviate, such as:
network latency (more effective caching of a single bundle, HTTP/1.0 connections),
performance constraints on the size of application modules (minification, tree-shaking),
ES2015 not supporting some features (bare imports),
and backwards compatibility with older module systems (transpilation of ES2015 Modules syntax).
However I'd like to know if it is possible to create a production JS web application in 2020 that doesn't use a bundler like webpack or Parcel and uses ES2015 Modules? A caveat being that a source-to-source compiler like Babel could still be used provided it preserves ES2015 Modules syntax. I'm not saying I would like to do this but for the sake of argument, what would be the downsides?
Client-side code does not have to be bundled when run in a modern browser, but if you're going to design your code into tons of small modules (for the sake of development efficiency and reuse), then it will be very inefficient to load if you don't use a bundler that can reduce the number of separate files that need to be loaded.
A bundler will be desirable if you design your client JS files for best modular development and thus don't design your client JS files for efficient delivery as the bundler can bundle things together for efficient delivery in a build process.
"Part of the JS SDK" is a matter of terminology and opinion, not facts so I won't really comment on that assertion.
It is certainly possible to design client-side JS files from the beginning for efficient client-side delivery and not use a bundler (like we used to do), but you will not be able to also design the layout of the files for modular development. A bundler allows you achieve both goals which is probably why they are so popular.
However I'd like to know if it is possible to create a production JS web application in 2020 that doesn't use a bundler like webpack or Parcel and uses ES2015 Modules?
Yes, it's possible without a bundler if you run in a browser that supports import and export.
I'm not saying I would like to do this but for the sake of argument, what would be the downsides?
As explained above, you would either give up efficient client-side loading or you would give up ideal modular design as the two have conflicting design parameters.
I was reading the Rails webpacker gem documentation where it says:
Webpacker makes it easy to use the JavaScript pre-processor and bundler webpack 4.x.x+ to manage application-like JavaScript in Rails. It coexists with the asset pipeline, as the primary purpose for webpack is app-like JavaScript, not images, CSS, or even JavaScript Sprinkles (that all continues to live in app/assets).
However, it is possible to use Webpacker for CSS, images and fonts assets as well, in which case you may not even need the asset pipeline. This is mostly relevant when exclusively using component-based JavaScript frameworks.
I'm trying to understand the rationale behind using both the older assets pipeline for CSS/images/JS-sprinkles if webpacker is capable of handling all of this?
I've read some other articles that walk me through using webpacker for all of this, but I don't understand the reasoning behind this decision.
Is this just to support legacy applications and eventually the older assets pipeline will go away and webpacker will be used for everything in Rails apps?
As a maintainer of an app that existed before Webpacker, I can give you one reason:
It's hard to migrate an existing frontend from Sprockets to Webpack.
Sprockets builds all JS into one big file with shared scope. Webpack isolates the scope of every JS module. To migrate to Webpack, you need to make sure your code still works with the scope isolation.
Which is often problematic, because in the Sprockets times you didn't have proper JS requires, either, and had to rely on globals or top-scope variables to share code and data between your JS source files.
Rails doesn't offer a painless transition path from Sprockets compilation to Webpack. So, it must support both.
But to answer your other question - going forward, you should use Webpacker if you have enough JS to make it worthwhile.
If your frontend is simple, you will skip some JS nuisances if you use Sprockets. Like if you want to add 10 lines of JS to your app, you might not want to setup a whole JS environment with dependency management and node_modules etc - which is the price of using Webpack/Webpacker. It would be even more senseless to manage a JS environment if all you want is to compile CSS and add digests to your image filenames - which Sprockets is perfectly capable of, without a package.json and anything else JS related.
Therefore, there's a second reason:
Webpacker is good for apps that have a significant frontend codebase. Sprockets is good for adding a bit of JavaScript to a traditional server-rendered app, and for apps with no JavaScript at all.
I have created quite a few npm packages, but I still don't know the right answer to this question: "Should JavaScript npm packages be minified?"
I have always understood that minifying minified code is a bad idea so have not done that in my npm packages. However, I see that some npm packages axios, styled-components provide minified versions of their "dist" files alongside unminified versions, while Lodash does not.
Which are right? Who would consume the minified versions?
It all depends on the environment of your package consumers
NodeJS
For a NodeJS audience your package does not have to be minified, since node runtimes normally have direct file access to the node_modules folder. No network transfers are required, and no additional code transformations are performed prior to running the code.
Bundlers / build pipelines
For consumption through a dev environment that uses a bundler in its build pipeline your package is best not minified. In most cases package consumers do implement their own minification process as part of their builds. Moreover, when providing your package in a module format for example:
the dependency tree of implementing codebases can be analyzed more accurately, which might lead to better tree-shaking performance.
Common dependencies across packages are actually the same symbols for all such packages (modules are 'singletons'). This helps with code splitting as well as with keeping bundles small.
The above statement relies on the assumption that, if multiple source files are included, minification is preceded by a bundling process. Minifying separate modules is uncommon. If you do provide separate modules, e.g. for a RequireJS runtime in the browser, minification is still relevant, since these files are mostly fetched over the network.
If you decide not to supply minified code, it's still advisable to run your own tests to see if a standard minification process - e.g. with UglifyJS - does not break the software.
Despite that it is for many consumers unnecessary to minify your code, it's still advisable to supply a minified bundle in addition to your regular distribution, just in case somebody could benefit from it.
For plugins / extensions for frameworks like Angular, Vue, Ember etc. it's usually unnecessary to minify your code, since they all implement their own build pipeline, often through a cli.
Script tags / CDN
These are the cases towards which minification is primarily targeted. If you're hosting a file on a CDN, or otherwise provide it over the web for direct <script> tag usage, what you see is what you get. In both cases the file will have to go over the network. Minification saves bytes.
Minification v.s. transpilation
A very important distinction is to be made between these two. Although minification is not always necessary, it is usually your responsibility to transpile any code that is unlikely to be 100% compatible with the target environments of your package audience. This includes:
Transpiling new ES20XX syntax to - probably - ES5
Polyfilling any ES20XX API implementations
Minification and bundling
If your package consists of a single bundle instead of a bunch of separate modules, minification is always a safe bet. Since a bundler will never try anything funny with a single module/entity (like tree-shaking), it's likely your code will technically not change at all by any build process.
Debugging
If you're going to distribute a minified bundle of your software, it would be nice to also ship a non-minified version for debugging purposes.
I have a large project entirely built in JavaScript, I have an ordered and "inside modularized" 5k lines .js file that's the engine of whole site.
Now I have to make other site (extension of this one) in which I'll have to repeat a lot of code, my question is, I've seen lot of possibilities using Browserify, CommonJS, etc. But that's not what I'm searching, I'm searching modularize JavaScript just like C/C++, making #includes with the files of the functions or functionalities and reuse code like that. I'm already doing this including other JS files in HTML, but that JS files are only variables and some arrays, not functionality of the site.
I use jQuery too, in that large 5k lines .js file I have almost all inside the jQuery document.ready event, that's bringing trouble too, because I'll have to make a document.ready event for every file?
I need some orientation please
CommonJS will let you require() modules, this is the foundation for the NodeJS module system. Browserify simplifies this implementation for use in browsers and even allows you to require Node modules (as long as they don't depend on binaries, the file system and other features a browser doesn't support).
var lib = require('someLibrary');
ECMAScript6 (aka: ES6) brings imports to javascript. While browsers don't fully support ES6 yet, you can use Babel to "transpile" ES6 to ES5. This ES5 will take advantage of CommonJS to replicate the importing behaviour.
import { SomeClass, someFunction, someValue } from 'some/library';
In all cases, your javascript will require some kind of pre-processing to transpile it into javscript a browser can understand. This usually means taking all your separate source files and bundling them into a single minified bundle file. This reduces the number of requests the browser has to make.
To handle all this transpiling and bundling, several popular build systems exist including Grunt, Gulp and Webpack. Grunt is older and typically slower because of it's configuration-based design. Gulp is simpler and faster because it relies on NodeJS streams. Webpack is the newest and most powerful, but at the cost of complexity. For what you're hoping to do, I'd recommend looking at Webpack since it can modularize not only your javascript but your stylesheets and other web assets.
http://webpack.github.io/docs/tutorials/getting-started/
Use webpack to bundle your code http://webpack.github.io/docs/tutorials/getting-started/
I maintain and collaborate on some JavaScript modules written in CommonJS that are in need of high-quality UMD wrappers.
The dependencies are sourced from npm but have at least CommonJS and AMD support (or I can add it).
The CommonJS version goes on npm The UMD wrapped module will be pushed to bower
The wrapper must work in browsers (AMD + globals), and in Node.js (any and other CommonJS systems if possible). Any automation should preferably happen using Grunt (I'm pretty handy in grunt).
I've spend ages trawling Google en SO but it is a huge mess.
Some hopeful ones that don't quite cut it (or I am missing something, which is entirely possible):
browserify
gluejs
grunt-umd
I'm finding desperate constructs like this everywhere: http://rathercurio.us/building-umd-modules-with-dependencies-with-browserify , but I'm not really cool with such hackery.
Any good tips on this? I'll take any pointer or link or tip.
Edit: clarification: that last thing said, the ideal solution should not require us to assemble chunks of boilerplate template code by hand and create new bugs. I cool with configuring and specifying stuff though.
Your 1st and last stop should be urequire.org, the Universal Module Converter that does much more that just converting CommonJS and AMD javascript modules to UMD (or AMD or CommonJS or a standalone using rjs/almond).
It allows you to manipulate Module's code and dependencies while converting: inject, replace or remove code and dependencies, export to global objects (window) or your bundle, inject & optionally merge common code (like initializations), add runtime information, minify and much much more.
Most of that using simple but hugely powerful declarations & optionally callbacks for fine grained manipulation. It works with standalone config files (.js, .coffee, .json, .yml etc) and as-is as a gruntjs config
uRequire compiles from source modules written in javascript, coffeescript, livescriped, coco & icedcoffeescript without any plugins.
Forget boilerplate, code ceremony and repeating requires. The conversion templates are based on the well known UMDjs but can be customized via declarations to hide or provide functionality.
uRequire is opensource, MIT license and hosted on github and authored by me :-)