Why is webpack spitting out 10,000 extra lines? - node.js

I'm using webpack via the default laravel setup after having run npm install, with the default config.
In webpack.mix.js, I have the following:
mix.js('resources/assets/js/init.js', 'public/js');
And resources/assets/js/init.js contains the following:
(function ($) {
$(function () {
$('.button-collapse').sideNav();
}); // end of document ready
})(jQuery);
Why, then, does webpack emit a whopping 10,000+ lines for this file?!:
Here's the output in a gist.
Did I completely misunderstand webpack, or is a laravel or webpack default messed up? I expect basically a copy of the JS, as npm run dev is not supposed to minify and it doesn't have any ES6 syntax in it... So what is this? The same thing works perfectly to compile scss to css if I add the appropriate line to the mix.

Short Answer
As best I can tell from what code you've given - yep, that's right.
Long Answer
What webpack does isn't just to compile your app to ES5. Rather, what is designed to do is package every dependency together in a single file so the end user downloads a single JS file.
In your original file, I assume at some point you define jQuery using require or some other method. (I'm not familiar with mix, but I assume at some point jQuery must be defined.) When you use require('jquery'), webpack transforms that into all of the jQuery source code - which is likely where almost all of the 10,000 lines of code are from.
We see your original code at the very end of the webpack bundle, starting at line 10,302:
/* WEBPACK VAR INJECTION */(function(jQuery) {(function ($) {
$(function () {
$('.button-collapse').sideNav();
}); // end of document ready
})(jQuery);
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1)))
As you can see, it's basically what you wrote, but now it defines jQuery using the previous 10,000 lines of code. This way, it's not referencing any external files.
Splitting your code
If you don't want your webpack bundle to have a bunch of jQuery at the top, you can split your code into vendor and app files. According to the laravel docs, that's done like this:
mix.js('resources/assets/js/init.js', 'public/js')
.extract(['jquery'])
Then, your bundle will output three files instead of one - one file containing the webpack manifest, one file containing all of the libraries (such as jQuery in this case), and one file containing the main app code (the five lines you wrote in resources/assets/js/init.js).

Related

Gulp + RequireJS Remove Vendor Files

I'm having a problem using Gulp to compile a RequireJS project properly. What I need to do is have gulp create a single distribution file that only includes the file necessary to have the application run.
In our application we are following a modular approach breaking out major pieces of functionality into different repos. So while developing my piece I have RequireJS including angular and many other vendor libraries that are common to all of the projects in the application. However when I go to move my piece into the larger application I no longer need these files in the final output since those dependencies also exist in that application (and having those extra libraries also makes the final distribution file over 300K).
I've tried creating another main.js (called gulp-main.js) file that only includes the dependencies that I need but when I run the gulp process it fails. I don't get an error but it seems to be failing because I'm not including the required dependencies for the project to build successfully. Below is the config object that is being passed to the RequireJS optimize method.
var config = {
baseUrl: 'app/',
mainConfigFile: 'app/main.js',
out: 'dist/app/output.js',
name: 'main'
};
Any ideas on what I could do to either remove the unnecessary vendor files or even split them into a single vendor and a single non-vendor file would really be appreciated. I have already tried using the modules array option but that does not produce the results that I am after since it seems to create a single file for each item defined not a single compiled JS file with all scripts contained within.
Thanks in advance.
When you don't want some file in your final output. add " ! " in Your gulp task's src
example :
gulp.src(['./app/*.js', '!./node_modules/**']) // '!./vendor-libraries-dest to igonore'

How to use babel runtime with large nodejs/express app

I want to use babel runtime in a big/complex nodejs app. I don't want to use the babel require hook because the app is big and when I have tried to use it I get the following error:
RangeError: Maximum call stack size exceeded
And I only want to transpile a few JS files, at least for now.
The babel docs are a bit cryptic for the runtime support. After installing babel-runtime, they provide:
require("babel").transform("code", { optional: ["runtime"] });
Where does that code get included? And is "code" truly just a string? I have tried to add that to my main app.js file (express 3 app). Unfortunately, that doesn't work.
I cannot totally understand your questions, but I think I can answer part of it.
As explained in the babel api, transform() function takes a string that is supposed to be source code to be transpiled, and returns an object including three properties:
code the code generated
map the source map for the code
ast the syntax tree
This means, if you want to transpile your code in a folder, for each file you want to transpile, you should read the file with fs utility, give it to transform() function, and write the value of the code property in the object returned, to your output folder.
To simplify the step to read files, you could use the function transformFile provided by babel.
As for the problem you mention with your express app, I cannot help, unless you provide more information.

Using require.js to collect and inline npm-installed modules into front end JS files

I have a project and installed for example underscore and marked via npm install. When I launch node in my project root folder, I can require both with var __ = require("underscore"), similar for marked. This is how I use both libraries in my backend, if needed. Now I want to write a myscript.js which is delivered to the browser, it's referenced for example in my index.html file. In this script, I want to use both mentioned libraries as well.
For this to work, I think there are two methods:
inline the required files (I think I prefer this)
copy the required js files into a separate directory, and use require.js in the browser.
In neither case I want to point a program to where the libs are found, similar to node, which knows what to do by just saying require("lib").
My questions are:
Did I understand this correctly?
Is grunt-contrib-requirejs exactly the the thing I need to automate this process?
Can someone provide me with a snippet of code or point me to a blog post or something? I think I lost the overview, I found the documentation but many things are confusing.
Here is what I have so far:
Configuration for my Grunt task:
requirejs: {
compile: {
options: {
baseUrl: "./",
name: "src/main.js",
out: "build/result.js"
}
}
}
My main.js:
var _ = require("underscore")
function foo(values)
{
_.find(values, function(value){ return false; });
}
The result:
function foo(e){_.find(e,function(e){return!1})}var _=require("underscore");define("src/main.js",function(){});
... not exactly what I thought.
While this does not answer my original question, I found out that using node modules is not exactly the way to go for frontend stuff, I found bower. Anyway, this whole thing is very frustrating.
Bower allows me to install required packages, and then there are modules for grunt which allow the JS files either to be "plugged" into the HTML document within a special section, or to be concatenated into one file. Bower-ready modules should ship with a bower.json file. This reliefes me fron the work of manually collecting all needed js files from the node_modules folder like I was afraid of in the question.

Use Require.js with an external concatenation tool

Currently, I use YUI-compressor to concatenate and compress all my JavaScript files. However, for various reasons, I want to start using Require.js.
In development, the files are not concatenated, so I can just use the default require(filepath) and define(modulename) with Require.js. But how do I handle the fact that in production, YUI will compress all the files, thus invalidating all the filepaths in my requires?
Let's say I have one main.js which requires module1.js. Here's what I want to do:
Development
require('path-to-module1')... // main.js
define('module1', function()})... // module1.js
Production
require('module1')... // main.js. here though, module1 and main.js are combined.
define('module1')... // yeah, still same file.
It's best to use and AMD optimizer, for example r.js, to concatenate your files. You can then also use r.js to minify, or you could YUI-comressor to minify .
Read more about r.js optimizer here http://requirejs.org/docs/optimization.html.
And check out this repo for a good example project for how to use Require.js and how to optimize it https://github.com/volojs/create-template. You can run node tools/r.js -o tools/build.js after cloning that repo to see optimizer in action - it will combine all js files in www to a single file.
Finally, you should never name your modules, like
define('module1', [], function () {});
Always use anonymous modules like so:
define(["jquery"], function ($) {});
or
define(function (require) { var $ = require("jquery"); });
AMD optimizer will use the name your modules for you such that they can all live in one file, but you won't have to worry about that.
Hope this helps.

Using require.js to load non-AMD files and files with other than .js extension

Is there any clean way to load files with other than js extension and not AMD content?
I use the enforceDefine config to make sure my actual AMD code works while developing.
So far I've managed to put together a plugin that sets enforceDefine to false, so I can load 3rd party libraries like so: require(['noamd!handlebars']). That doesn't seem too much hacky to me but I'd like to know if there's a better way.
I'm currently testing the noext plugin and it does its job but also in a kind of a hacky way. I've noticed that it applies the noext parameter twice to the url (test.txt?noext=1&noext=1). I can live with that but optimally I'd like to git rid of all extra parameters. Can that be done?
To load files that aren't JS (such as .handlebars, .mustache) then the text plugin will suit your purposes.
To load normal js files you can use RequireJS as a script loader:
require(['full/path/to/file.js'], function(){
// Fired when file is loaded but if non AMD
// no value will be passed to this function
});
If you would like to treat the non-AMD file as a module, then you can use the shim config to implement it.
you can append a ?MEH=BLAH to the end to stop the .js appending
eg
requirejs.config({
paths: {
"dynamicstripconfig": "../php/domain/config.php?dynamic=1"
}
});
Additionally there a plugin for that as well, but doesn't support paths -> https://github.com/millermedeiros/requirejs-plugins
Added a issue with fix for path support -> https://github.com/millermedeiros/requirejs-plugins/issues/47
If your file isn't actually a dynamic js file then use the text plugin -> https://github.com/millermedeiros/requirejs-plugins

Resources