Config Map package name prefixed with namespace + colon - node.js

I see an example in Angular2 startup project's System.Config.JS, it likes below:
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
'app': 'app',
// angular bundles
'#angular/core': 'npm:#angular/core/bundles/core.umd.js',
'#angular/common': 'npm:#angular/common/bundles/common.umd.js',
'#angular/compiler': 'npm:#angular/compiler/bundles/compiler.umd.js',
'#angular/platform-browser': 'npm:#angular/platform-browser/bundles/platform-browser.umd.js',
'#angular/platform-browser-dynamic': 'npm:#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'#angular/http': 'npm:#angular/http/bundles/http.umd.js',
'#angular/router': 'npm:#angular/router/bundles/router.umd.js',
'#angular/forms': 'npm:#angular/forms/bundles/forms.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
},
My question is: map seems using config path's alias like 'npm', and suffixed it with colon ":", then prepend this string to the package file name, like npm:#angular/forms/bundles/forms.umd.js in the example.
However I looked up over the SystemJS's config API and RequireJS's config, but I did not find any documentation for this usage. Has anyone ever worked on this and can provide some useful link or documentation for that. Thank you in advance.

The relevant part of the documentation is this: https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#paths
The doc says:
Paths allow creating mappings that apply after map configuration
This is what Angular2 config does. The colon ":" has no special meaning, it's just to make it more obvious that all the modules come from npm.
For example when you import module #angular/core:
The #angular/core is mapped to npm:#angular/core/bundles/core.umd.js thanks to the map option.
npm:#angular/core/bundles/core.umd.js is mapped to node_modules/#angular/core/bundles/core.umd.js where the npm: is replaced with node_modules/ thanks to the paths option.
You could use any other string than npm: it I'd work the same way.

Related

How to dynamically import package.json dependencies based on environment variables?

How could I add a script to my package.json file that would allow me to dynamically use a local file instead of a package version based on an environment variable?
"dependencies": {
"dynamic-dependency": "$(process.env.NODE_ENV !== 'dev' ? '^1.0.7' : 'file:../local-path-to-package')"
}
You can't do this in package.json, which is non-executable JSON file. The JSON variant used in package.json doesn't even support comments :). The purpose of package.json is to specify which dependencies are installed into node_modules, and that's it. With those dependencies installed, they can be used by Node at runtime, which locates them using the module resolution algorithm:
If the module identifier passed to require() is not a core module, and does not begin with '/', '../', or './', then Node.js starts at the parent directory of the current module, and adds /node_modules, and attempts to load the module from that location. Node.js will not append node_modules to a path already ending in node_modules.
So you can't use NPM/package.json for this. But, I see that you tagged your question with React, so if you are using Webpack, you can solve this issue in your Webpack config. This can be done with resolve.alias:
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
'dynamic-dependency': process.env.NODE_ENV !== 'dev' ? 'dynamic-dependency' : path.resolve(__dirname, '../local-path-to-package'),
},
},
};
I have not used other JS bundlers, but I would have to think Parcel/Rollup etc support this kind of configuration as well.

What is the use system.config.js file in angular 2?

what does var map,packages, var config do. And also the explain all the configuration property for the map and package object. Is there any documentation for available configuration?
Here is my System Config File
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'#angular/core': 'npm:#angular/core/bundles/core.umd.js',
'#angular/common': 'npm:#angular/common/bundles/common.umd.js',
'#angular/compiler': 'npm:#angular/compiler/bundles/compiler.umd.js',
'#angular/platform-browser': 'npm:#angular/platform-browser/bundles/platform-browser.umd.js',
'#angular/platform-browser-dynamic': 'npm:#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'#angular/http': 'npm:#angular/http/bundles/http.umd.js',
'#angular/router': 'npm:#angular/router/bundles/router.umd.js',
'#angular/forms': 'npm:#angular/forms/bundles/forms.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'fscopy': 'npm:fs-extra/lib/copy/index.js',
'file-system': 'npm:file-system/file-system.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
fs: {
defaultExtension: 'js'
}
}
});
})(this);
I would like to follow up on #Sajeetharan answer by giving an in depth example. So pretend you want to install a new module, we will use angular2-highcharts as an example. For reference here is the doc for hightcharts.
as you know you begin by running your npm command npm install angular2-highcharts --save
a. Now you will see the installed module in your node_modules folder
OK so you have installed a new module to use, now you have to tell your app where to find this new module and how to load it. This is where you systemjs.config.js come into play.
a. First you need to "map" or tell your app where to find this new module. in this case it looks like this... 'angular2-highcharts': 'node_modules/angular2-highcharts',
now lets break this down a little. 'angular2-highcharts': this is saying if you are referencing angular2-highcharts then use the following path of 'node_modules/angular2-highcharts'
b. Next is the Package portion. this is now saying, ok you have mapped where to find this new module, now what inside of this new module folder would you like to run? in this case its the `index.js' and we define that like so...
angular2-highcharts': {
main: './index.js',
defaultExtension: 'js'
}
Now that you have properly installed the module and referenced it in your systemjs.config.js you can call the import in your 'app.modules' component and in whatever component you wish.
Edit
forgot to explain config. Config is just a way to define folders or file with a short hand value. In your config npm: node_modules, is basically saying you can short hand node_modules with npm. this is shown in you mapping statements like so.... 'npm:#angular/core/bundles/core.umd.js' rather than writing out node_modules/#angular/core/bundles/core.umd.js
system.config.js is the one which allows to load modules(node modules) compiled using the TypeScript compiler.map refers to the name of modules to JS file that contains the JavaScript code.
If You are using Angular-Cli, should not need a systemjs.config. Everything is should take care by angular-cli.

Can't find node_modules after deployment

This title might be a bit misleading but please bear with me for a while.
I have made a simple Angular2 app on visual studio 2015 and now I have published it on Azure.
Having node_modules in the development environment was perfect but after deploying it shows error saying can't find node_modules.
Here is how I am referring in my development env in index.html-
<!-- Polyfill(s) for older browsers -->
<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/reflect-metadata/Reflect.js"></script>
<script src="/node_modules/systemjs/dist/system.src.js"></script>
<script src="/systemjs.config.js"></script>
Its also referred in system.config.js-
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': '/app', // 'dist',
'#angular': '/node_modules/#angular',
'angular2-in-memory-web-api': '/node_modules/angular2-in-memory-web-api',
'rxjs': '/node_modules/rxjs'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade',
];
// Individual files (~300 requests):
function packIndex(pkgName) {
packages['#angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['#angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setPackageConfig);
// No umd for router yet
packages['#angular/router'] = { main: 'index.js', defaultExtension: 'js' };
var config = {
map: map,
packages: packages
};
System.config(config);
})(this);
The error makes sense as I have a .gitignore file which doesn't let the node_modules to deploy to server.
Can someone please assist as to how I can run it after deploying and what change could be done with the above references in order to make it work.
I have not used SystemJS, but your bounty has enticed me to try answering anyway, since it looks like you still need an answer. :)
After glancing through some SystemJS docs, it looks like your index.html needs to be different for development vs production use. This is what the docs show for development:
<script src="systemjs/dist/system.js"></script>
<script>
SystemJS.import('/js/main.js');
</script>
And this is what they show for production (notice the first line has a different src path):
<script src="systemjs/dist/system-production.js"></script>
<script>
SystemJS.import('/js/main.js');
</script>
More importantly, take note that node_modules is not referenced in either case, nor should it be. If you have your code and configuration set up correctly, SystemJS (like other build tools) will package everything you need without any additional <script> tags. Instead, you should import your shims (and similar) from within your code somewhere. For example, in their Webpack guide (Webpack is a another build tool filling a similar role to SystemJS) the Angular team shows a polyfills.ts file that imports their shims, then they include the polyfills file into the build within their webpack configuration.
I'm sorry I can't offer more specific advice about SystemJS in particular, but hopefully this answer is enough to point you in the right direction.
You either have to deploy node_modules as a part of your package or have a script run npm install for you to get the packages from your package.json
To get the packages in your package.json file do npm install --save package-you-want-to-install
Then you can have your startup script install from the package json by trying the script on this link https://github.com/woloski/nodeonazure-blog/blob/master/articles/startup-task-to-run-npm-in-azure.markdown
One thing you could do is install the packages needed on Azure server via Kudu dashboard.
Go to https://yoursitename.scm.azurewebsites.net
Then Debug console -> CMD
Go to home\site\wwwroot directory
Type npm install
This will install the needed packages for the Angular 2 app to run on Azure server.
Don't use system.config.js
You need to bundle it first. Don't upload node_modules in Azure. To bundle refer below link.
How to bundle an Angular app for production
Once you bundle dist folder will create. You can upload the dist folder in Azure.
npm install your deps on prod env ..
npm i --production

Uglify or concat a JavaScript file conditionallly

I have in my Scripts folder a "Lib" folder and an "App" folder.
The Lib folder contains 3rd part library JavaScript files. Some of these are minified without the original sources, others we have the original sources for.
The App folder contains all of our own JavaScript files, all of which are not minified.
I'm new to Grunt but I have a gruntfile which does the following:
Uglifies all the JS files in the Lib folder and produces minified versions with sourcemaps.
Uglifies all the JS files in the App folder and produces minified versions with sourcemaps.
Obvious problem: some of the files in the Lib folder are minified, so minifying them again/generating source maps is a bad idea and can fail for various reasons.
My solution: I run Uglify only on .js files in the Lib folder into lib-unmin.min.js. I then concat all the already minified files into a lib-min.min.js file, then I concat both those files together to get lib.min.js.
The new problem
What if I can't concat the already minified scripts to the end of the other minififed scripts without it breaking?
I have a dependency issue like this:
scripts/lib/a.js (required for b to run)
scripts/lib/b.min.js (required for c to run)
scripts/lib/c.js (required for the App scripts to run)
If I have an array of these file paths in my gruntfile, in that order, what's the easiest way of uglifying/concating all the files into a single minified JS file in that order, making sure we don't attempt to minify the minified file?
What do other developers do in similar situations?
Thanks!
I like to concat the files then uglify all of them together. This way uglify makes sure there aren't duplicate variable values overriding each other when it compresses the variable names.
You can bundle as many files as you want in the concats. Make different concat groups to uglify together and maintain the 'first, second, third, ...' order like this:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
app: {
options: {
sourceMap: true,
sourceMapName: 'build/maps/map.map'
},
files: {
'build/app.min.js': ['build/js/app-first-unmin.js', 'build/js/app-second-min.js', 'build/js/app-third-unmin.js']
}
}
},
concat: {
options: {
separator: ';'
},
firstUnminified: {
src: [
'lib/underscore.js'
],
dest: 'build/js/app-first-unmin.js'
},
secondMinified: {
src: [
'lib/moment.min.js'
],
dest: 'build/js/app-second-min.js'
},
thirdUnminified: {
src: [
'lib/favico.js'
],
dest: 'build/js/app-third-unmin.js'
}
},
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['concat:firstUnminified', 'concat:secondMinified', 'concat:thirdUnminified','uglify']);
};

Use RequireJS config file as the build file?

I've got some paths configured in require-config.js as follows:
var require = {
baseUrl: '/javascript',
paths: {
'jquery': 'jquery/jquery-1.8.1.min'
// etc. -- several paths to vendor files here
},
}
I am trying to get the optimization working for deployment. The docs say I should have a build.js that looks something like this:
({
baseUrl: 'javascript',
paths: {
'jquery': 'jquery/jquery-1.8.1.min'
},
name: 'main',
out: 'main-build.js'
})
Is there a way to have the optimizer read my config file instead of (or in addition to) build.js? I don't want to have to manually keep the paths configured the same in both files if they change.
I tried to just run node r.js -o path/to/require-config.js, but it threw an error, "malformed: SyntaxError: Unexpected token var"
Edit: for clarification, my require-config.js file is the config only, not my main module. I did this so I could use the same configuration but load a different main module when unit testing.
You'll need to adjust the way your config options are defined. Taken from the RequireJS documentation:
In version 1.0.5+ of the optimizer, the mainConfigFile option can be used to specify the location of the runtime config. If specified with the path to your main JS file, the first requirejs({}), requirejs.config({}), require({}), or require.config({}) found in that file will be parsed out and used as part of the configuration options passed to the optimizer:
So basically you can point your r.js build file to your config options that will also be shared with the browser.
You will need to make use of the mainConfigFile option
For other's reference:
https://github.com/jrburke/r.js/blob/master/build/example.build.js
The build settings (no need to repeat your config.js lib inclusions here):
baseUrl: 'app',
name: 'assets/js/lib/almond', // or require
// Read config and then also build it into the app
mainConfigFile: 'app/config.js',
include: ['config'],
// Needed for almond (and does no harm for require)
wrap: true,

Resources