I'm using the RequireJS optimiser to minify and concatenate my code. At the moment r.js doesn't minify a lot of my scripts because of the nested dependencies.
I want to include nested dependencies for:
All dependencies inside: 'js/services'
All nested dependencies for a list of specific JavaScript files
Note: I do realise that there is the option findNestedDependencies: true but this looks for absolutely every dependency across all JavaScript files in the app where as I only want to do this for certain JavaScript files and folders as I have a set of files which are always used on every page/view.
My current build file looks like:
({
baseUrl: '../static/js',
mainConfigFile: '../static/js/main.js',
name: 'main',
out: '../static/js/scripts.min.js',
paths: {
requireLib: 'vendor/require/require.min'
},
include: 'requireLib'
})
I have been following this tutorial to get the optimiser running:
http://www.youtube.com/watch?v=m6VNhqKDM4E
You can use include to specify all dependencies you want to force into the output file:
// ...
include: ['requireLib', 'js/services/dep1', 'js/services/dep2'],
// ...
I don't think there's a way to include entire folder (something like "js/services/*"), though.
Since in my project I had many dynamic dependencies I wanted to include in the output I ended up creating an "js/services/_all.js" module which lists files in its directory, for example:
define([
'./dep1',
'./dep2'
],
function () {
// this module imports all modules from current folder so
// there's no need to list every single file in the build config
});
and then configuring r.js with:
// ...
include: ['requireLib', 'js/services/_all'],
// ...
Related
We have an application that has multiple environments and is about to have multiple vendors. I understand that the typical flow is to run webpack --env.NODE_ENV=myenvironment, however, this will become highly inefficient very quickly.
Ultimately, the simplicity of my goal is to copy the environment.json file into the output folder and use it so that I can perform transformations in Octopus Deploy rather than having to run multiple builds.
In other words, I'd like to utilize a single environment.json file for the purpose of providing variable substitutions in Octopus Deploy. Here's a sample environment.json:
{
"production": false,
"baseUrl": "http://myapp.com",
"appId": "MyAppId"
}
Now in AngularJS code, I'm configuring constants that utilize these values:
import * as environment from '../../environment.json';
console.log(environment.baseUrl); // http://myapp.com
angular.module('app')
.constant('environment', environment);
So far, so good.
The problem is that now if I modify the values inside of dist/environment.json (note this is in the output folder), it does not update the values. For example, if I change the value of baseUrl to http://myapp-dev.com, the console.log will still print http://myapp.com.
Here's the relevant code in my webpack.config.js:
Rules
...
{
test: /\.json$/,
use: 'json-loader',
exclude: [/environment\.json$/]
},
...
Plugins
...
new CopyWebpackPlugin([{
from: 'environment.json'
},
...
The above code successfully copies the environment.json file to the output folder, but the rest of the code in the output folder is NOT using it. For whatever reason it appears to still be coupled with webpack.
CopyWebpackPlugin just copies a file - nothing more happens here and Webpack won't use that internally. The static JSON import is most likely part of you main bundle js.
Instead of trying to dynamically replace some parts of the build define a external module. This way you have the flexibility to provide whatever globals you want to the browser environment and webpack will know where to find them during runtime.
Ok, I am complete lost with this. I have just started using Typescript with Grunt JS and need some help.
I have a working Grunt file thats runs my TS and then a uglify process for site ready files, here is the config:
ts: {
default: {
files: {
'/js/builds/main.js': ['/typescript/main/build.ts'],
'/js/builds/public.js': ['/typescript/public/build.ts']
}
},
options: {
target: 'ES5',
fast: 'never',
sourceMap: false,
allowJs: true,
declaration: false,
module: 'amd'
},
},
'uglify': {
options: {
preserveComments: 'some',
},
my_target: {
files: {
'src/js/main.js': ['/js/builds/main.js'],
'src/js/public.js': ['/js/builds/public.js']
}
}
},
watch: {
'JS': {
files: [
'/js/**/*.js',
'/typescript/**/*.ts',
'/typescript/**/**/*.ts'
],
tasks: ['ts', 'uglify'],
options: {
spawn: false,
},
}
}
So now I am working on my Typescript files, but I having a lot of issues, I want to use Typescript as a module system but to output into a single file, right now its set to AMD, which needs Require JS of which I dont know.
Right now I don't have the time to learn Typescript and Require JS. So where is what I have got right now,
test.js:
export class testMe {
constructor() { }
LogingData() {
console.log( 'Data being logged...' );
}
}
Then in my build ts file,
import {testMe} from "./clients/clients";
However this needs Require JS or module loading system in order to get it to run? I have tried using commonJs but it seems support for that was removed in Typescript 1.8 (I am using 2.0).
So how do I get my Grunt / Typescript into a single standard ES5 complied code, while using modules for Typescript?
Many thanks
UPDATE
This question & answer, Typescript compile to single file does not give an answer for how to setup grunt to use Typescript into a single file! Plus the answer states that Typescript 1.8+ will fix that issue - But the version I am using does not.
I am using Grunt to compile the TS code into one standard javascript file, without the use of System or Require JS. So I can use that within my HTML code.
The end goal would be to have two single files. To explain I have lots of single .ts files for two sections, one main and the other public - I have not work on the public section, just the main one, so all my tests I been on that section.
So to layout my file/folder path:
js/
builds/
main.js < targer end file
public.js <- target end file
typescript
main/
settings/
classA.ts
somethingelse.ts
othersection/
something.ts
buildMain.ts <- *1
*1 This file then takes all the ts files, via imports (not sure if thats the correct way) and then builds the complete standard single .js file.
I hope that explains my query in more detail.
Thanks
UPDATE 2:
I would just like to add that I am getting a single file, e.g. main.js but that is not a standard Javascript complied file. I don't want to use Require JS or any other external module loading system.
I want to use external .ts files has modules import them into a 'build' file and have that file compile down to a standard self contained javascript file without the need to include require js or anything else.
Hope that clears it up a little more..
Thanks.
I believe you can use --outfile to get everything into one file. The trick is to remove import and export statements and use /// <reference path="path/to/file.ts" /> on the first lines to declare the dependency / ordering relationships. Since it is the import/export statements that produce the calls to CommonJS or Require, omitting them prevents their generation.
Ref: https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
For two output files, you'll probably need two tsconfig.json. (I might be incorrect here.)
If you don't bother with .d.ts files you can simply use just --module=commonjs(it is and will be supported) to compile each file into .js and then browserify to concat all modules together.
I'm using CLI scripts instead of grunt but it should be obvious what it does:
$ ./node_modules/.bin/tsc --module commonjs main.ts
$ ./node_modules/.bin/browserify main.js -o bundle.js
Then you can run it like any other JavaScript from browser or CLI using node.
There's also --outFile option for tsc but this is limited only to amd and systemjs modules so I think it's easier to stick to commonjs and browserify.
browserify is an amazing tool. You can generate UMD module with --standalone parameter that works also as global or exclude any external dependencies.
I highly recommend you to read the Official Handbook: https://github.com/substack/browserify-handbook
That's something I've struggled with for more than a year now, I don't get how we are supposed to load a JS file that contains several AMD modules at once to avoid making as many HTTP requests as there are JS files.
Since we have to define each module separately in the RequireJS config, how is it possible to load only one merged JS file containing all modules at once?
Here is my RequireJS loader: https://gist.github.com/Vadorequest/9553eaf27ac1f469cf63
In that file, what I'd like to merge are:
The requirejs libs (domReady, text, markdown)
The shared source code between the server and the client (Lang, MessageLang... View)
Because these files will increase progressively and increase the number of HTTP calls.
You will have to do this in a build step. Have you consider using RequireJS Optimizer?
The documentation is pretty solid and you will need to add a couple of parameters to your require config:
{
baseUrl: ".",
paths: {
jquery: "some/other/jquery"
},
name: "main",
out: "scripts.js"
}
This will generate one file (scripts.js) with all your files in it. There is also a bundle option if you like to group some files together requirejs bundles
I personally use gulp to take care of my build process so I actually use gulp-requirejs-bundler but the same principles apply.
I have a directory like below:
/folder/b.js
/folder/jQuery.js
/folder/a.js
/folder/sub/c.js
I want to minify all these js files in one js file in order:
jQuery.js -> a.js -> b.js -> c.js
Q:
1.How can I do it via grunt-contrib-uglify?(In fact, there are lots of files, it is impractical to specify all source filepaths individually)
2.btw, How can I get unminified files when debug and get minified single file when release and no need to change script tag in html(and how to write the script tag)?
Good questions!
1) Uglify will reorder the functions in the destination file so that function definitions are on top and function execution on bottom but it seems that it will preserve the order of the function executions.
This means that the function jQuery runs to define its global functions will be put first if you make sure jQuery is mentioned first in Uglify's config in the Gruntfile.
I use this config:
uglify: {
options: {
sourceMap: true
},
build: {
files: {
'public/all.min.js': ['public/js/vendor/jquery-1.10.2.min.js', 'public/js/*.js'],
}
}
}
2) I don't think there is one definite way to accomplish this. It depends on what web framework, templating framework and what kind of requirements you have. I use express + jade and in my main jade layout I have:
if process.env.NODE_ENV === 'production'
script(src='/all.min.js')
else
script(src='/js/vendor/jquery-1.10.2.min.js')
script(src='/js/someScript.js')
script(src='/js/otherScript.js')
In my package.json I have:
"scripts": {
"postinstall": "grunt"
},
This means that when I run npm install on deploy (on Heroku) grunt is run to minify/concat files and when the app is started with NODE_ENV=production the minified client side javascript is used. Locally I get served the original client side javascripts for easy debugging.
The two downsides are:
I have to keep the two lists of script files in sync (in the Gruntfile and in the layout.js) I solve this by using *.js in the Gruntfile but this may not suite everyone. You could put the list of javascripts in the Gruntfile and create a jade-template from this but it seems overkill for most projects.
If you don't trust your Grunt config you basically have to test running the application using NODE_ENV=production locally to verify that the minification worked the way you intended.
This can be done using the following Grunt tasks:
https://github.com/gruntjs/grunt-contrib-concat concatenates
files
https://github.com/gruntjs/grunt-contrib-uglify minifies
concatenated files
EDIT
I usually run all my files through a Grunt concatenation task using grunt-contrib-concat. Then I have another task to uglify the concatenated file using grunt-contrib-uglify.
You're probably not going to like this, but the best way is to define your js source files as AMD modules and use Requirejs to manage the order in which they load. The grunt-contrib-requirejs task will recurse your dependency tree and concatenate the js files in the necessary order into one big js file. You will then use uglify (actually r.js has uglify built-in) to minify the big file.
https://github.com/danheberden/yeoman-generator-requirejs has a good example gruntfile and template js files to work from.
EDIT
I've recently started using CommonJS modules instead of AMD since it's much closer to the ES6 module spec. You can achieve the same results (1 big complied+concatenated js file) by running commonjs modules through Browserify. There are plugins for both grunt and gulp to manage the task for you.
EDIT
I'd like to add that if your site is written using ES6 that Rollup is the best new concatenating package. In addition to bundling your files, it will also perform tree shaking, removing parts of libraries you use if included via an import statement. This reduces your codebase to just what you need without the bloat of code you'll never use.
I don't think you can do this with the uglify task alone, but you have a multitude of choices which might lead to your desired outcome.
A possible workflow would be first concatenating (grunt-contrib-concat) the files in order into one single file, and put this concatenated file through uglify. You can either define the order for concat in your Gruntfile, or you use on of those plugins:
First one would be https://github.com/yeoman/grunt-usemin, where you can specify the order in your HTML file, put some comments around your script block. The Google guys made it and it's pretty sweet to use.
Second one would be https://github.com/trek/grunt-neuter, where you can define some dependencies with require, but without the bulk of require.js. It requires changes in your JS code, so might not like it. I'd go with option one.
I ran into the same issue. A quick fix is just to change the filenames - I used 1.jquery.min.js, 2.bootstrap.min.js, etc.
This might be only remotely related to your question but I wanted something similar. Only my order was important in the following way:
I was loading all vendor files (angular, jquery, and their respective related plugins) with a wildcard (['vendor/**/*.js']). But some plugins had names that made them load before angular and jquery. A solution is to manually load them first.
['vendor/angular.js', 'vendor/jquery.js', 'vendor/**/*.js]
Luckily angular and jquery handle being loaded twice well enough. Edit: Although it's not really the best practice to load such large libraries twice, causing your minified file unnecessary bloat. (thanks #Kano for pointing this out!)
Another issue was client-js the order was important in a way that it required the main app file to be loaded last, after all its dependencies have been loaded. Solution to that was to exclude and then include:
['app/**/*.js', '!app/app.js', 'app/app.js']
This prevents app.js from being loaded along with all the other files, and only then includes it at the end.
Looks like the second part of your question is still unanswered. But let me try one by one.
Firstly you can join and uglify a large number of js files into one as explained by the concat answer earlier. It should also be possible to use https://github.com/gruntjs/grunt-contrib-uglify because it does seem to have wildcards. You may have to experiment with 'expand = true' option and wildcards. That takes care of your first question.
For the second part, say you joined and uglified into big-ugly.js
Now in your html you can add following directives:
<!-- build:js:dist big-ugly.js -->
<script src="js1.js"></script>
<script src="js2.js"></script>
<!-- etc etc -->
<script src="js100.js"></script>
<!-- /build -->
And then pass it through the grunt html preprocessor at https://www.npmjs.com/package/grunt-processhtml as part of your grunt jobs.
This preprocessor will replace the entire block with
<script src="big-ugly.js"></script>
Which means that the html file with be semantically equivalent - before and after the grunt jobs; i.e. if the page works correctly in the native form (for debugging) - then the transformed page must work correctly after the grunt - without requiring you to manually change any tags.
This was #1469's answer but he didn't make it clear why this works. Use concat to put all js files into one, this module does this in the order of file names, so I put a prefix to the file names based on orders. I believe it even has other options for ordering.
concat: {
js: {
options: {
block: true,
line: true,
stripBanners: true
},
files: {
'library/dist/js/scripts.js' : 'library/js/*.js',
}
}
},
Then use uglify to create the minified ugly version:
uglify: {
dist: {
files: {
'library/dist/js/scripts.min.js': [
'library/js/scripts.js'
]
},
options: {
}
}
},
If your problem was that you had vendors which needed to be loaded in order (let's say jquery before any jquery plugins). I solved it by putting jquery in its own folder called '!jquery', effectively putting it on top of the stack.
Then I just used concat as you normally would:
concat: {
options: {
separator: ';',
},
build: {
files: [
{
src: ['js/vendor/**/*.js', 'js/main.min.js'],
dest: 'js/global.min.js'
}
]
}
},
Is it possible to import individual modules from within an optimized RequireJS/r.js bundle?
I have a javascript project broken up into two separate components - 'MyLibrary' and 'MyApplication'
MyLibrary consists of two separate modules, 'MyModule1' and 'MyModule2'.
In development mode, I can import each of these modules using RequireJS with the normal define(['MyLibrary/MyModule1'],function(){}) syntax from MyApplication.
However once running MyLibrary through r.js, this no longer appears to be possible - there doesn't appear to be a way to reference the internal modules directly anymore?
I can see from the compiled/optimized source that there are define() blocks for each module, however RequireJS within My Application doesn't appear to be able to reference these directly.
Is this possible, or will I need to bundle my entire application into a single file for this to work.
Edit: The RequireJS optimization phase is being done my the Play framework, and I have minimal control over the build config.
({appDir: "javascripts",
[info] baseUrl: ".",
[info] dir:"javascripts-min", mainConfigFile: "javascripts/build.js", modules: [{name: "main"}]})
In order to use the modules from the library, you need to instruct RequireJS how to find this modules. In main.js you need to have something like this:
require.config({
// ...
paths: {
// ...
'MyLibraryBundleName': 'dist/MyLibraryFile',
// ...
},
// ...
bundles: {
//...
'MyLibraryBundleName': ['MyLibrary/MyModule1', 'MyLibrary/MyModule2'],
//...
}
});
When MyApplication is referencing a module like this:
define(['MyLibrary/MyModule1'],function(){})
... as you mention, RequireJS will look for 'MyLibrary/MyModule1' and will find it into the 'bundles' section and after that will check the 'path' section to locate the actual file 'dist/MyLibraryFile' which will be loaded.