Link to global node modules folder from Angular2 app - node.js

I wish to have a centralised Node modules folder (using npm update -g to save to C disk) instead of the usual local folder which is contained in the app, due to Angular2 CLI installing 125mb+ worth of Node modules in the local folder.
So in the typescript files we previously imported the angular core like so:
import { Component } from '#angular/core';
But obviously this doesnt work, is it possible to put a prefix or hard URL somewhere to tell the app to search in the global folder for the modules?

Modify SystemJs configuration (usually systemjs.config.js file), so it maps #angular to you centralized node_modules\#angular folder, instead of local one.
var map = {
'app' : 'app',
'#angular' : 'C:/node_modules/#angular', // path to centralized repo
};

Here is what your systemjs.config file should be :
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'src',
'#angular': 'global location'
};
// 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' },
//can add as per your requirement
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router',
'#angular/router-deprecated',
'#angular/testing',
'#angular/upgrade',
];
// add package entries for angular packages in the form '#angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
})(this);

Related

Bundling files in "src" folder into "public" folder using webpack

How to Bundle all the files inside “src” folder and replace the existing bundled files inside “Public” folder in any Node.js web app?
My project structure is similar to this: https://github.com/googlearchive/friendlypix-web
For javascript files, you should have at least one entry-point for your application in order to bundle it.
Example of webpack.config.json with one entrypoint src/index.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public'),
},
};
More information about bundling one or many entry-points : https://webpack.js.org/concepts/entry-points/
Furthermore, if you have imported static assets (images, css, saas, fonts...) in your javascript files, you need to add some configuration and eventually install webpack loaders to bundle them.
For example, for CSS assets :
Install webpack loaders via npm install --save-dev style-loader css-loader
Update webpack configuration
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
More information about asset management : https://webpack.js.org/guides/asset-management/
Finally, you may need to bundle static files or directories that are not imported in your javascript files and you want to copy them as they are.
In this case, you could use the copy-webpack-plugin :
Install plugin via npm install copy-webpack-plugin --save-dev
Update webpack configuration
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
...
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" },
{ from: "other", to: "public" },
],
}),
],
...
}
More info about copy-webpack-plugin : https://webpack.js.org/plugins/copy-webpack-plugin/
I really recommend you to take a look at the official webpack documentation which covers topics including creating production bundles, code splitting, caching and other tips and hints.

How do I bundle bcrypt in a yarn workspace monorepo using webpack and serverless-framework? [duplicate]

I'm using yarn workspaces where the root directory has a package directory with all my repos. Each repo has its own node_modules directory containing its dependencies. The root node_modules directory contains all the dev dependencies for the whole project as well as all other dev related things such as webpack.config files. Webpack uses hot module reload for the express server package.
The problem I have is, how to configure webpack externals to exclude all node_modules directories through the whole project, not just in the root?
webpack-node-externals doesn't seem to work given this scenario.
Error message:
WARNING in ./packages/servers/express/node_modules/colors/lib/colors.js
127:29-43 Critical dependency: the request of a dependency is an expression
WARNING in ./packages/servers/express/node_modules/express/lib/view.js
79:29-41 Critical dependency: the request of a dependency is an expression
Webpack config:
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const StartServerPlugin = require('start-server-webpack-plugin');
module.exports = {
entry: [
'babel-polyfill',
'webpack/hot/poll?1000',
path.join(__dirname, '../packages/servers/express/server/index.js')
],
watch: true,
target: 'node',
externals: [
nodeExternals({
whitelist: ['webpack/hot/poll?1000']
})
],
resolve: {
alias: {
handlebars: 'handlebars/dist/handlebars.js'
}
},
module: {
rules: [
{
test: /\.js?$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new StartServerPlugin('server.js'),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env': { BUILD_TARGET: JSON.stringify('server') }
})
],
output: {
path: path.join(__dirname, '../packages/servers/express/.build'),
filename: 'server.js'
}
};
If using yarn workspaces with webpack-node-externals a better solution than setting modulesFromFile: true is to use the following externals setting in your webpack config:
externals: [
nodeExternals(),
nodeExternals({
modulesDir: path.resolve(__dirname, 'path/to/root/node_modules'),
}),
],
Essentially using two instances of nodeExternals. 1 for the package node_modules and one for the root node_modules.
Thanks to #blackxored I was able to fix it on my project.
In your webpack config file do the following:
import nodeExternals from 'webpack-node-externals'
Then add
externals: [
nodeExternals({
modulesFromFile: true,
}),
],
Yarn workspaces hoist compatible modules to the root node_modules directory leaving any incompatible (different semver, etc.) modules with the dependent workspace's node_modules directory. If a package is requested without using a relative path it is either native, from node_module's, or possibly a symlinked package from one of your workspaces. You probably want all of those packages to be external.
how to configure webpack externals to exclude all node_modules directories through the whole project, not just in the root?
I would try using a function with webpack's external option. You are passed the context of the require, the name of the module requested, and a callback to indicate whether this particular import (require) should be considered external.
externals: [
(ctx, req, cb) => {
if (!/node_modules/.test(ctx) && req[0] !== '.') {
// Assumes you have defined an "entries" variable
let notAnEntry = (path) => {
return Object.keys(entries).every((entry) => {
return entries[entry] !== path
});
};
if (notAnEntry(require.resolve(req))) {
// This module is external in a commonjs context
return cb(null, `commonjs ${req}`);
}
}
cb();
}
]

Why do I get "TypeError: Reflect.getOwnMetadata is not a function"

I'm working on File Upload with Angular2 and Node.js with ng2-File-Upload
but while running my project i got an error related to Reflect.getOwnMetadata
here is the error shown :
and here is my systemjs.config.js
(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',
/** Path for ng2-file-upload */
'ng2-file-upload' : 'npm:ng2-file-upload'
/** Path for ng2-file-upload */
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './transpiled-js/main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
'angular-in-memory-web-api': {
main: './index.js',
defaultExtension: 'js'
},
/** Configuration for ng2-file-upload */
'ng2-file-upload' : {
main: './ng2-file-upload.js',
defaultExtension: 'js'
}
/** Configuration for ng2-file-upload */
}
});
})(this);
This is the scenario when I faced the exact same issue:
I had two TypeScript files with the same name (say, FileUploadService.ts) residing in two different locations. One was for handling server logic (residing in a server directory), and the other in a public directory for file upload through an Angular service.
The problem was that I was importing the wrong service in a location where the ng2-file-upload package was used, which in turn depends on Angular modules - which were never being imported.
This meant that the file where Reflect.getOwnMetadata is defined somewhere was unavailable during the Typescript compilation.
Please make sure you reference the correct file in the correct location which might be the case for you too.

How to use webpack with a monorepo (yarnpkg workspaces)

I'm using yarn workspaces where the root directory has a package directory with all my repos. Each repo has its own node_modules directory containing its dependencies. The root node_modules directory contains all the dev dependencies for the whole project as well as all other dev related things such as webpack.config files. Webpack uses hot module reload for the express server package.
The problem I have is, how to configure webpack externals to exclude all node_modules directories through the whole project, not just in the root?
webpack-node-externals doesn't seem to work given this scenario.
Error message:
WARNING in ./packages/servers/express/node_modules/colors/lib/colors.js
127:29-43 Critical dependency: the request of a dependency is an expression
WARNING in ./packages/servers/express/node_modules/express/lib/view.js
79:29-41 Critical dependency: the request of a dependency is an expression
Webpack config:
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const StartServerPlugin = require('start-server-webpack-plugin');
module.exports = {
entry: [
'babel-polyfill',
'webpack/hot/poll?1000',
path.join(__dirname, '../packages/servers/express/server/index.js')
],
watch: true,
target: 'node',
externals: [
nodeExternals({
whitelist: ['webpack/hot/poll?1000']
})
],
resolve: {
alias: {
handlebars: 'handlebars/dist/handlebars.js'
}
},
module: {
rules: [
{
test: /\.js?$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new StartServerPlugin('server.js'),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env': { BUILD_TARGET: JSON.stringify('server') }
})
],
output: {
path: path.join(__dirname, '../packages/servers/express/.build'),
filename: 'server.js'
}
};
If using yarn workspaces with webpack-node-externals a better solution than setting modulesFromFile: true is to use the following externals setting in your webpack config:
externals: [
nodeExternals(),
nodeExternals({
modulesDir: path.resolve(__dirname, 'path/to/root/node_modules'),
}),
],
Essentially using two instances of nodeExternals. 1 for the package node_modules and one for the root node_modules.
Thanks to #blackxored I was able to fix it on my project.
In your webpack config file do the following:
import nodeExternals from 'webpack-node-externals'
Then add
externals: [
nodeExternals({
modulesFromFile: true,
}),
],
Yarn workspaces hoist compatible modules to the root node_modules directory leaving any incompatible (different semver, etc.) modules with the dependent workspace's node_modules directory. If a package is requested without using a relative path it is either native, from node_module's, or possibly a symlinked package from one of your workspaces. You probably want all of those packages to be external.
how to configure webpack externals to exclude all node_modules directories through the whole project, not just in the root?
I would try using a function with webpack's external option. You are passed the context of the require, the name of the module requested, and a callback to indicate whether this particular import (require) should be considered external.
externals: [
(ctx, req, cb) => {
if (!/node_modules/.test(ctx) && req[0] !== '.') {
// Assumes you have defined an "entries" variable
let notAnEntry = (path) => {
return Object.keys(entries).every((entry) => {
return entries[entry] !== path
});
};
if (notAnEntry(require.resolve(req))) {
// This module is external in a commonjs context
return cb(null, `commonjs ${req}`);
}
}
cb();
}
]

systemjs not able to load my module

systemjs.config.js:
/**
* 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',
'mystartup_commons': 'npm:mystartup_commons'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
mystartup_commons: {
defaultExtension: 'js'
}
}
});
})(this);
This is the index.js it is pointing to:
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./helpers"));
__export(require("./model2"));
Error in browser :
GET
http://localhost:3000/node_modules/mystartup_commons/dist/src/helpers
404 (Not Found)
GET
http://localhost:3000/node_modules/mystartup_commons/dist/src/helpers
404 (Not Found)
You are pointing mystartup_commons to a file, not a package. Thus the defaultExtension doesn't have much effect.
Try jspm and it will show you how to get things setup.
This issue may also "interest" you as you are working with TS and SystemJS:
https://github.com/systemjs/systemjs/issues/1587

Resources