I am using Node v8.12.0 on Mac (although I've seen this issue with Node 9.x versions, and also on Linux).
I am developing Angular 6 app, and am running dev builds with --watch
flag. The watch will run and can rebuild the app maybe 4 or 5 times, then Node crashes with the following output:
<--- Last few GCs --->
[34201:0x104000000] 273927 ms: Mark-sweep 1309.4 (1430.5) -> 1309.2 (1431.0) MB, 1296.0 / 0.0 ms allocation failure GC in old space requested
[34201:0x104000000] 275358 ms: Mark-sweep 1309.2 (1431.0) -> 1309.2 (1424.0) MB, 1430.8 / 0.0 ms last resort GC in old space requested
[34201:0x104000000] 276946 ms: Mark-sweep 1309.2 (1424.0) -> 1309.2 (1423.5) MB, 1587.7 / 0.0 ms last resort GC in old space requested
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x1c5f3a825879 <JSObject>
1: fromString(aka fromString) [buffer.js:~298] [pc=0x2234a1ca140b](this=0x1c5ffcc022d1 <undefined>,string=0x1c5f6f8dffa1 <Very long string[784654]>,encoding=0x1c5ffcc022d1 <undefined>)
2: from [buffer.js:177] [bytecode=0x1c5f43e4aac9 offset=11](this=0x1c5f8a5b5c51 <JSFunction Buffer (sfi = 0x1c5f3a87e159)>,value=0x1c5f6f8dffa1 <Very long string[784654]>,encodingOrOffset=0x1c5ffcc022d1 <u...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [/usr/local/bin/node]
2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/usr/local/bin/node]
3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/local/bin/node]
4: v8::internal::Factory::NewRawTwoByteString(int, v8::internal::PretenureFlag) [/usr/local/bin/node]
5: v8::internal::String::SlowFlatten(v8::internal::Handle<v8::internal::ConsString>, v8::internal::PretenureFlag) [/usr/local/bin/node]
6: v8::String::WriteUtf8(char*, int, int*, int) const [/usr/local/bin/node]
7: node::StringBytes::Write(v8::Isolate*, char*, unsigned long, v8::Local<v8::Value>, node::encoding, int*) [/usr/local/bin/node]
8: node::Buffer::New(v8::Isolate*, v8::Local<v8::String>, node::encoding) [/usr/local/bin/node]
9: node::Buffer::(anonymous namespace)::CreateFromString(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
10: 0x2234a02d4067
11: 0x2234a1ca140b
12: 0x2234a023d1d6
13: 0x2234a018535f
I have tried adding --max_old_space_size=12000
also, but it has not seemed to make any difference. I'm not sure where to look for the cause of the issue, or how to even begin debugging in Node. Any assistance would be hugely appreciated!
Some background: it was Angular 5 app with ejected config, and I have updated it to Angular 6, with the same config, and the app itself is working as expected. It is only since updating to Angular 6 that this issue started to arise.
For reference, here are the dependency and devDependency parts of the package.json:
"dependencies": {
"@angular/animations": "6.1.10",
"@angular/cdk": "6.4.7",
"@angular/common": "6.1.10",
"@angular/compiler": "6.1.10",
"@angular/core": "6.1.10",
"@angular/forms": "6.1.10",
"@angular/http": "6.1.10",
"@angular/material": "6.4.7",
"@angular/platform-browser": "6.1.10",
"@angular/platform-browser-dynamic": "6.1.10",
"@angular/router": "6.1.10",
"@ng-idle/core": "6.0.0-beta.3",
"@ng-idle/keepalive": "6.0.0-beta.3",
"@ngrx/effects": "6.1.2",
"@ngrx/entity": "6.1.2",
"@ngrx/router-store": "6.1.2",
"@ngrx/store": "6.1.2",
"@ngrx/store-devtools": "6.1.2",
"@swimlane/ngx-datatable": "14.0.0",
"@types/crypto-js": "3.1.37",
"@types/moment": "2.13.0",
"angular2-toaster": "6.1.0",
"angulartics2": "7.2.0",
"core-js": "2.5.7",
"crypto-js": "3.1.9-1",
"hammerjs": "2.0.8",
"immutable": "3.8.2",
"jquery": "2.2.4",
"moment": "2.19.1",
"ng2-charts": "1.6.0",
"ngx-zendesk-webwidget": "0.1.3",
"node-waves": "0.7.6",
"normalize.css": "3.0.3",
"rxjs": "6.3.3",
"sass": "1.15.1",
"zone.js": "0.8.26"
},
"devDependencies": {
"@angular-builders/custom-webpack": "7.0.0",
"@angular-devkit/build-angular": "0.11.0",
"@angular/cli": "7.0.6",
"@angular/compiler-cli": "6.1.10",
"@angular/language-service": "6.1.10",
"@types/jasmine": "2.5.53",
"@types/jasminewd2": "2.0.2",
"@types/node": "6.0.60",
"autoprefixer": "9.3.1",
"chromedriver": "2.38.2",
"clean-webpack-plugin": "1.0.0",
"codelyzer": "4.5.0",
"copy-webpack-plugin": "4.6.0",
"css-loader": "1.0.1",
"cssnano": "4.1.7",
"exports-loader": "0.7.0",
"file-loader": "2.0.0",
"istanbul-instrumenter-loader": "2.0.0",
"jasmine-allure-reporter": "1.0.2",
"jasmine-core": "2.6.2",
"jasmine-marbles": "0.4.0",
"jasmine-spec-reporter": "4.2.1",
"karma": "3.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "2.0.1",
"karma-jasmine": "1.1.2",
"karma-jasmine-html-reporter": "0.2.2",
"karma-spec-reporter": "0.0.32",
"lint-staged": "8.1.0",
"loader-utils": "1.1.0",
"mini-css-extract-plugin": "0.4.5",
"npm-run-all": "4.1.5",
"postcss-custom-properties": "8.0.9",
"postcss-loader": "3.0.0",
"postcss-url": "8.0.0",
"pre-commit": "1.2.2",
"process": "0.11.10",
"protractor": "5.4.1",
"protractor-console": "3.0.0",
"protractor-jasmine2-html-reporter": "0.0.7",
"puppeteer": "1.6.0",
"raw-loader": "0.5.1",
"rxjs-tslint": "0.1.5",
"sass-loader": "7.1.0",
"selenium-server-standalone-jar": "3.8.1",
"source-map-loader": "0.2.4",
"style-loader": "0.23.1",
"stylelint": "9.6.0",
"stylelint-config-recommended": "2.1.0",
"ts-mockito": "2.3.1",
"ts-node": "3.2.0",
"tslint": "5.7.0",
"typescript": "2.9.2",
"uglifyjs-webpack-plugin": "2.0.1",
"url-loader": "1.1.2",
"webpack": "4.24.0",
"webpack-bundle-analyzer": "3.0.3",
"webpack-cli": "3.1.2",
"webpack-concat-plugin": "3.0.0",
"webpack-dev-server": "3.1.10",
"webpack-filter-warnings-plugin": "^1.2.1",
"yargs": "8.0.1"
}
Lastly, here is the custom webpack configuration I am using (which worked flawlessly in Angular 5):
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const autoprefixer = require('autoprefixer');
const postcssUrl = require('postcss-url');
const cssnano = require('cssnano');
const customProperties = require('postcss-custom-properties');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NormalModuleReplacementPlugin } = require('webpack');
const { AngularCompilerPlugin } = require('@ngtools/webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const postcssPlugins = function (env) {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /@preserve|@license|[@#]\s*source(?:Mapping)?URL|^!/i;
const baseHref = '';
const deployUrl = '';
const minimizeOptions = {
preset: [
'default',
{
mergeLonghand: false,
discardComments: { remove: (comment) => !importantCommentRe.test(comment) }
}
]
};
return [
postcssUrl({
url: (URL) => {
// Only convert root relative URLs, which CSS-Loader won't process into require().
if (!URL.url.startsWith('/') || URL.url.startsWith('//')) {
return URL.url;
}
if (deployUrl.match(/:\/\//)) {
// If deployUrl contains a scheme, ignore baseHref use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${URL.url}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${URL.url}`.replace(/\/\/+/g, '/');
}
else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${URL.url}`.replace(/\/\/+/g, '/');
}
}
}),
autoprefixer(),
customProperties({ preserve: true })
].concat(env === 'prod' ? [cssnano(minimizeOptions)] : []);
};
const builder = (customer, prodEnv) => {
let plugins = [
new ProgressPlugin(),
new NoEmitOnErrorsPlugin(),
new FilterWarningsPlugin({
exclude: /System.import/
}),
new CleanWebpackPlugin(['target/classes/static/' + customer]),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
new CopyWebpackPlugin([
{
context: 'src/main/angular',
to: '',
from: {
glob: 'assets/**/*',
dot: true
}
},
{
context: 'src/main/angular',
to: '',
from: {
glob: 'favicon.ico',
dot: true
}
}
], {
ignore: [
'.gitkeep',
'**/.DS_Store'
],
debug: 'warning'
}),
//Replace the actual environment file with the correct one passed in via env args
new NormalModuleReplacementPlugin(/(.*)\environments\/environment(\.*)/, function(resource) {
resource.request = resource.request.replace('environments/environment',
`environments/${customer}/environment.${prodEnv}`);
}),
//Replace the actual chart-colors file with the correct one based on customer
new NormalModuleReplacementPlugin(/(.*)\environments\/chart-colors.json/, function(resource) {
resource.request = resource.request.replace('environments/chart-colors.json',
`environments/${customer}/chart-colors.json`);
}),
//Replace the actual lang file with the correct one based on customer
new NormalModuleReplacementPlugin(/(.*)\environments\/lang.json/, function(resource) {
resource.request = resource.request.replace('environments/lang.json',
`environments/${customer}/lang.json`);
}),
//Replace the actual scss file with the correct one based on customer
new NormalModuleReplacementPlugin(/(.*)\environments\/styles.scss/, function(resource) {
resource.request = resource.request.replace('environments/styles.scss',
`environments/${customer}/styles.scss`);
}),
new AngularCompilerPlugin({
mainPath: 'main.ts',
platform: 0,
sourceMap: (prodEnv === 'dev') ? true : false,
tsConfigPath: 'src/main/angular/tsconfig.app.json',
skipCodeGeneration: true,
compilerOptions: {}
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
"window.jQuery": 'jquery',
Hammer: 'hammerjs/hammer'
})
];
let devPlugins = [
new CircularDependencyPlugin({
exclude: /(\\|\/)node_modules(\\|\/)/,
failOnError: false
}),
new SourceMapDevToolPlugin({
filename: '[file].map[query]',
moduleFilenameTemplate: '[resource-path]',
fallbackModuleFilenameTemplate: '[resource-path]?[hash]',
sourceRoot: 'webpack:///',
exclude: ['vendor.js']
}),
new BundleAnalyzerPlugin({
generateStatsFile: true
})
];
let prodPlugins = [
new UglifyJsPlugin({
parallel: true,
sourceMap: false
})
];
plugins = prodEnv === 'dev'
? plugins.concat(devPlugins)
: plugins.concat(prodPlugins);
return {
resolve: {
extensions: [
'.ts',
'.js'
],
modules: [
'./node_modules'
],
symlinks: true,
alias: {
"rxjs/" : './node_modules/rxjs/_esm2015/'
},
mainFields: [
'browser',
'module',
'main'
]
},
resolveLoader: {
modules: [
'./node_modules'
]
},
entry: {
main: [
'./src/main/angular/main.ts'
],
polyfills: [
'./src/main/angular/polyfills.ts'
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'initial',
test: path.join(process.cwd(), 'node_modules'),
name: 'vendor',
enforce: true,
filename: 'vendor.chunk.js'
}
}
}
},
output: {
path: path.join(process.cwd(), 'target', 'classes', 'static', customer),
filename: '[name].bundle.js',
chunkFilename: '[id].chunk.js',
crossOriginLoading: false
},
module: {
rules: [
{
test: /\.html$/,
loader: 'raw-loader'
},
{
test: /\.(eot|svg|cur)$/,
loader: 'file-loader',
options: {
name: '[name].[hash:20].[ext]',
limit: 10000
}
},
{
test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
loader: 'url-loader',
options: {
name: '[name].[hash:20].[ext]',
limit: 10000
}
},
{
test: /\.css$/,
use: [
'exports-loader?module.exports.toString()',
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postcssPlugins(prodEnv)
}
}
]
},
{
test: /\.css$/,
include: [
path.join(process.cwd(), `src/main/angular/environments/${customer}/styles.scss`)
],
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postcssPlugins(prodEnv)
}
}
]
},
{
test: /\.scss$/,
include: [
path.join(process.cwd(), `src/main/angular/environments/${customer}/styles.scss`)
],
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postcssPlugins(prodEnv)
}
},
{
loader: 'sass-loader',
options: {
sourceMap: false,
precision: 8,
includePaths: [path.join(process.cwd(), 'src', 'main', 'angular')]
}
}
]
},
{
test: /\.ts$/,
loader: '@ngtools/webpack'
}
]
},
mode: (prodEnv === 'prod') ? 'production' : 'development',
plugins: plugins,
node: {
fs: 'empty',
global: true,
crypto: 'empty',
tls: 'empty',
net: 'empty',
process: true,
module: false,
clearImmediate: false,
setImmediate: false
},
devServer: {
historyApiFallback: true
},
watchOptions: {
aggregateTimeout: 500
}
};
};
module.exports = {
build: builder
}
One way to build Angular application is with NodeJS or Java, and the other method is in which we first build Angular, serve the static content with NGINX. If we are using it with NodeJS, then we also need to deal with server code. For example, the index. html page must be loaded with node.
Maybe your PC running several processes in the Background. So you need to stop all the node process that are running. and then restart nodemon.
Angular, the Angular CLI, and Angular applications depend on npm packages for many features and functions. To download and install npm packages, you need an npm package manager.
Once you build your app for production you won't need Node. js because the final bundles are just static HTML, CSS, and JavaScript that can be served by any server or a CDN. That being said, if you are building a full-stack web application with Angular, you may need Node.
This is known as memory leak which says you try to reserve a huge memory!
Note that Allocating more memory (--max_new_space_size
and/or --max_old_space_size
) won't solve the main problem, although may help to continue working on a memory consuming application.
As you know, in javascript applications, build is a process to export minified bundles where they come from dependencies and your individual codes. In some cases, compatibility issues among dependencies (mismatch versions) may reserve more memory! For example a user found out lodash v4.14.70 is not compatible with TS 2.7 out of the box. Although you don't use lodash, such this issue can be expected.
Also, you must be familiar with cases in javascript where memory leaks happen, then figure out what is using too much memory in your application. I recommend you to Record Heap Snapshots too. I list some cases when a memory leak may occur (at a glance):
Since your application worked fine before updating to Angular6, the main affection comes from your new dependencies. I think this is necessary to cleanup your project from unused dependencies as first step, perhaps by some tool like dependency-check (I have never tested it). Then try to migrate the project from Angular5 to Angular6 again with Angular Update Guide. Then check the compatibility among dependencies. At the time of writing this answer, I have not found any tool to find compatible versions but as a trick, You can employ versions which are released at the same period of time (concurrent).
We've seen this happen on occasion with Angular 5 as well. Our solution (workaround?) is to run ng serve with the max_old_space_size
param.
node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng serve --aot
setting --max_old_space_size=8192
works for me, but it is really a good solution for one part developers. For another we can try another solution
This is my solution, it requires people to use git bash as terminal if on windows, but it would be easy to change if needed (just use the cmd file instead):
In my project root I have a folder called scripts and in it a file called ng.sh, which is a copy from node_modules/.bin/ng
but with more allowed RAM to be used
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" --max_old_space_size=8192 "./node_modules/@angular/cli/bin/ng" "$@"
ret=$?
else
node --max_old_space_size=8192 "./node_modules/@angular/cli/bin/ng" "$@"
ret=$?
fi
exit $ret
Then in my package.json
I do:
"scripts": {
"build-prod": "bash ./scripts/ng.sh build --prod --aot --env=prod"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With