Rebuild Typescript file with pm2 watch - node.js

I've added pm2 to one of the repos I work with because I want to restart the local server on crashes and such. App engine handles that for us in production (hopefully 🤞). It's an amazing service really, and I was hoping to replace nodemon with it, but I can't get it to automate the Typescript build on restart.
I was messing around with scripts, and configs, with no luck. I basically need it to to run /node_modules/.bin/tsc to rebuild the dist folder on save. Otherwise, I end up with a stale file that's reloaded for no reason other than change detection.
I haven't found anything online, maybe I'm not looking hard enough, and I don't want to run ts-node as an alternative. I tried running nodemon before and after, with no avail.
Some files:
ecosystem.config.js
apps: [
{
name: "example",
script: ".",
exp_backoff_restart_delay: 1000,
watch_option: {
persistent: true,
ignoreInitial: true,
}
};
package.json
"pm2-start": "pm2 start && pm2 logs",
I tried adding the npm run build before pm2 start and it worked the first time, but not on reloads.
Thanks in advance.

Related

Run nextjs application in the background

I have an application built with nextJs and this application should work on a local server (Windows).
my customer told me that he needed this application to work in the background after searching I found that I needed to use a package called pm2 and when I used it gives me an error and I found that I needed to make some configurations for it and I can't found any helping resources, please help 💔
I found that to run nextJs application in the background you will need a custom configuration
you need to download the pm2 globally in your system
create a file with the name ecosystem.config.js in the root folder next to the package.json file
you need to put your config data in this file which would be something like this
module.exports = {
apps: [
{
name: "inventory_test",
script: "node_modules/next/dist/bin/next",
args: "start -p 3333", //running on port 3000
watch: false,
},
],
};
you should set the name as the name you want to see when you check
the list of pm2
the problem will be solved when you set the script as I did in the code above to be more precise the default run of pm2 is to go to the node js folder in the system and try to make start for the application using npm directly but this is the problem we need to make it use the node runner from the nextjs itself or something like this so we change the script as above
after that, we set the arguments that we should run after the npm and in my example is the arg start and choose the port for our application too
and now we make our config
NOTES
you should make build before you start the application
to run the project you will open the folder of the project in the terminal || cmd || cmder and run the command pm2 start ecosystem.config.js

PM2 run nodejs sveltekit app with options

I have an app that i bult with npm run build, with sveltekit, everything works fine, but i have to specify the ORIGIN like it says here https://github.com/sveltejs/kit/tree/master/packages/adapter-node, to make it run otherwise i run in to this problem "Cross-site POST form submissions are forbidden".
I run it like this and it works fine ORIGIN=http://myorigin node out/index.js.
Now i need to register it to PM2 but i find nothing to run it with the origin parameter.
I have also tried to set the ORIGIN keu in the .env file, and installing dotenv, but i still need to run this command: node -r dotenv/config build, with options, and i cant make it start from PM2.
Is there a way to do this?
Thanks
i found this and it worked https://pm2.keymetrics.io/docs/usage/application-declaration/
module.exports = {
apps : [{
name : "app",
script : "ORIGIN=http://myorigin node out/index.js"
}]
}

How to get pm2 process to watch after it has been stopped/ restarted?

My pm2 process starts using their default ecosystem file structure:
ecosystem.config.js
module.exports = {
apps: [{
env: {
NODE_ENV: "development"
},
error_file: "./logs/error.log",
ignore_watch: ["logs", "node_modules"],
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
name: "my-app",
out_file: "./logs/output.log",
script: "./server.js",
watch: true
}]
}
I start the process with pm2 start ecosystem.config.js and that works fine, with the app reloading on file changes.
But when I stop the process with pm2 stop ecosystem.config.js, and then start it again with pm2 start ecosystem.config.js, pm2 does not watch for files, despite the display column of watching being enabled.
The only way to start the process up again and have the watch work is to delete the pm2 process, and then start up a new one again.
Am I missing something to make a stop or restart work with watch?
Thanks.
The pm2 watch & restart documentation had the answer (must have glossed over it on first read):
Restart with --watch will toggle the watch parameter.
Looks like omitting that --watch flag on already-existing pm2 instances will not toggle the watch parameter in the ecosystem.config.js file. The watch parameter is only toggled on initial process execution, not subsequent ones.
So stopping the process, then starting again with pm2 start ecosystem.config.js --watch does the trick!
Try adding
watch_options: {
"usePolling": true
}
See here: http://pm2.keymetrics.io/docs/usage/watch-and-restart/
This is not a PM2 specific option, but rather a chokidar option which is used by PM2.
The documentation of those options can be found here.
https://stackoverflow.com/users/7575111/nulldev
watch_options: {
"usePolling": true
}
The answer was helpful to me as a trial environment that doesn't cost me restarting the app every time

Setting up Angular Universal App for development

I have created a project with Angular-CLI. (using command: ng new my-angular-universal).
Then I carefully followed all the instructions from https://github.com/angular/angular-cli/wiki/stories-universal-rendering
It builds for --prod and works fine. But there are no instructions on how I can set up a --dev build and have it served with --watch flag.
I tried removing --prod flags from npm "scripts", and it doesn't even run in dev mode. It builds fine but when I open it in browser this is what I see (directly printed to response):
TypeError: Cannot read property 'moduleType' of undefined
at C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:7069:134
at ZoneDelegate.invoke (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:105076:26)
at Object.onInvoke (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:6328:33)
at ZoneDelegate.invoke (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:105075:32)
at Zone.run (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:104826:43)
at NgZone.run (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:6145:69)
at PlatformRef.bootstrapModuleFactory (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:7068:23)
at Object.renderModuleFactory (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:52132:39)
at View.engine (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:104656:23)
at View.render (C:\Users\Mikser\documents\git\my-angular-universal\dist\server.js:130741:8)
the versions of npm packages that I use are currently the latest:
#angular/* - #5.2.*
#angular/cli #1.7.3
except for ts-loader, had to downgrade it because it wasn't working:
ts-loader #3.5.0
So if anyone has any info on how to make this work, it would be very appreciated! Or maybe you know some project templates with Angular Universal App configured for both --dev and --prod builds and ability to --watch?
For development, run npm run start which triggers ng serve. The current setup has hot module reloading so it will watch for your changes and update your dev view. I used the same instructions and got it working here https://github.com/ariellephan/angular5-universal-template
In short, for development, run npm run start and look at http://localhost:4200.
For production, run npm run build:ssr and npm run serve:ssrand look at http://localhost:4000
As contributors have pointed out, it might not be the most efficient and fastest way to develop, but nevertheless I did not want to accept workarounds. Besides, hosting front and back on separate servers brings up CORS issues, and I never planned my app to run on separate hosts, I wanted it all on the same host together with API methods.
The problem with --dev build was this:
when building with the following command:
ng build --app 1 --output-hashing=false (note that there is no --prod flag)
AppServerModuleNgFactory turned out missing in the ./dist-server/main.bundle
I imagine that this relates to the ahead of time(--aot) compilation which is the default behavior if you are building for --prod. So the instructions from https://github.com/angular/angular-cli/wiki/stories-universal-rendering included instructions to configure express server for production build only. And since there is no need for server to be able to dynamically render html templates the working --dev build command would be:
ng build --app 1 --output-hashing=false --aot
and this gets rid of the TypeError: Cannot read property 'moduleType' of undefined
Now to watch this whole mess:
run these in separate command windows:
ng build --watch
ng build --app 1 --output-hashing=false --aot --watch
webpack --config webpack.server.config.js --progress --colors --watch
And for the server to restart on change, you have to install nodemon package and run it like this:
nodemon --inspect dist/server (--inspect if you wish to debug server with chrome)
Some other important stuff:
Angular/CLI has a command to generate necessary scaffolding for a universal app:
ng generate universal
and it generates a fixed version of main.ts that avoids client angular bootstrap issue:
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
});
a problem that I stumbled upon once I implemented TransferState
There are basically two parts - the server and the UI. While developing the UI, I simply use ng serve. That means when I make changes in my code in the IDE, the browser refreshes automatically. And, here the server part is not used.
I do prod build and run the server only for final testing to see if everything works as expected (No error due to any 3PP library DOM manipulation or AOT related issues, etc.)
Here, I have created a skeleton structure of an Angular Universal project. As I extensively use Vagrant and Docker in my projects, I run the server in a Docker container within the Vagrant guest system. And for development of the UI, I don't run the server. Simply, the ng serve is used.
If you look into my structure in the above Github link, you'll find the details as to how to run it for development and production in the Readme file.
The web server handler server.ts uses the server bundle
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
That's why the server bundle needs to be compiled before you can compile the server.ts file.
So having a watch system would mean
watching/recompiling the client bundle
watching/recompiling the server bundle
recompiling the server.ts once the server bundle is created
All of them take some time (especially if you do it with aot)
I'd recommend, like Saptarshi Basu mentionned, to develop as best as you can with ng serve and check with angular universal every so often.
Otherwise, it should be possible do achieve what you want with some kind of tasks (grunt/gulp/...) which triggers sequentially ng build ... and recompilation of server.ts file.
It is a bit messy no doubt, as we preferably wish for one command to rule them all.
I came up with a somewhat OK solution where my output will be:
dist/browser
dist/ng-server
Using the executable npm-run-all package (I find it working a lot better on windows machines than concurrently does) I run the three watch tasks: browser, ng-server and nodeJS. Watching node has a pre-task defined that simply runs a small utility/helper/file that watches for the existence of a dist/ng-server folder and terminate itself once found.
For all of this to work (based on the universal-starter repo as of november 2018) there's a couple of modifications to package.json required. Primarily, to support the --watch flag on ng run commands we need to update the compiler-cli (if memory serves), ng update --all should take care of that, giving you the latest angular/cli version in the process (assuming you have a recent cli version installed globally).
package.json
ng update --all
angular 6+
angular/cli 7+
yarn add/npm install the following
chokidar
npm-run-all
(runs our tasks in parallel with the -p flag. -p kills all processes, -l gives each running task a specific color and name in the console)
ts-node (runs nodejs in it's ts-format)
nodemon // for restarting ts-node
add something similar to my util/await-file.js (after some consideration I added my own file-watcher code below even though it wasn't exactly written with the intentions to be put up on display...)
modify your package.json scripts like below
modify your angular.json to match your folder names, following my examples, mainly the "server"'s outputPath should be changed from dist/server to dist/ng-server.
package.json scripts
"dev": "npm-run-all -p -r -l watch:ng-server watch:browser watch:node",
"watch:browser": "ng build --prod --progress --watch --delete-output-path",
"watch:ng-server": "ng run ng-universal-demo:server --watch --delete-output-path",
"watch:node": "yarn run watch:file-exist && yarn run ts-node",
"ts-node": "nodemon --exec ts-node server.ts -e ts,js",
"watch:file-exist": "node utils/await-file.js",
util/await-file.js
const chokidar = require('chokidar');
const fs = require('fs');
const path = require('path');
const DIR_NAME = 'ng-server';
const DIST_PATH = './dist';
// creates dist folder if it doesn't exist - prior to adding it to the watcher.
if (!fs.existsSync(DIST_PATH)) {
fs.mkdirSync(DIST_PATH);
}
const watcher = chokidar.watch('file, dir', {
ignored: '*.map',
persistent: true,
awaitWriteFinish: {
stabilityThreshold: 5000,
pollInterval: 100
}
});
const FOLDER_PATH = path.join(process.cwd(), 'dist');
watcher.add(FOLDER_PATH);
console.log(`file-watcher running, waiting for ${DIST_PATH}/${DIR_NAME}`);
function fileFound() {
console.log(`${DIR_NAME} folder found - closing`);
watcher.close();
process.exit();
}
watcher
.on('add', function (filePath) {
const matchWith = path.join('dist', DIR_NAME);
const paths = filePath.split(path.sep);
const fileName = paths[paths.length - 1];
if ((filePath.indexOf(matchWith) >= 0)
&& fileName.indexOf('.js') > fileName.length - 4) {
fileFound();
}
})
.on('error', error => console.log(`Watcher error: ${error}`));
"npm run start" and using "http://localhost:4200" works for me. Even with Angular 10

Auto reloading a Sails.js app on code changes?

Currently is seems that for any code change in a sails.js app you have to manually stop the sails server and run sails lift again before you can see the changes.
I was wondering if there is any way when running in development mode to automatically restart the sails server when it detects a code change?
You have to use a watcher like forever, nodemon, or something else...
Example
Install forever by running:
sudo npm install -g forever
Run it:
forever -w start app.js
To avoid infinite restart because Sails writes into .tmp folder, you can create a .foreverignore file into your project directory and put this content inside:
**/.tmp/**
**/views/**
**/assets/**
See the issue on GitHub:
Forever restarting because of /.tmp.
You can use sails-hook-autoreload
Just lift your app as normal, and when you add / change / remove a model or controller file, all controllers and models will be reloaded without having to lower / relift the app.
For example with nodemon to watch api and config directories
.nodemonignore contents
views/*
.tmp/*
.git/*
Run the command after creating .nodemonignore
$> nodemon -w api -w config
Example for supervisor to ignore 3 directories
$> supervisor -i .tmp,.git,views app.js
If you're using Sails 0.11, you can install this hook to automatically reload when you change models or controllers (views do not require reloading):
npm install sails-hook-autoreload
https://www.npmjs.com/package/sails-hook-autoreload
install nodemon globally or locally.
npm install nodemon --save
npm install nodemon -g
install sails locally in you project as follows
npm install sails --save
then change package.json
from
"scripts": {
"debug": "node debug app.js",
"start": "node app.js"
},
to
"scripts": {
"debug": "node debug app.js",
"start": "node app.js",
"dev": "export NODE_ENV=development && nodemon --ignore 'tmp/*' app.js && exit 0"
},
then
npm run dev
I had the same problem and I have solved it using grunt-watch and grunt-forever with sails#beta tasks. The result is 4 grunt commands:
UPDATE: tasks are available in the current sails version (it's no longer beta :>)
start Starts the server
stop Stops the server
restart Restarts the server
startWatch Starts the server and waits for changes to restart it (using grunt-watch). This is probably your solution, but the other commands are also useful.
Here's the code - I'm using sails#beta, which includes a tasks directory, I don't know if this is included in previous versions:
First of all you have to install forever in your sails directory:
npm install grunt-forever --save-dev
tasks/config/forever.js Configure forever task.
module.exports = function(grunt) {
grunt.config.set('forever', {
server: {
options: {
index: 'app.js',
logDir: 'logs'
}
}
});
grunt.loadNpmTasks('grunt-forever');
};
tasks/config/watch.js (edit) Edit watch task in order to add a new rule
// api and assets default rules
,
server: {
// Server files to watch:
files: [
'api/**/*',
'config/**/*'
],
// Restart server
tasks: ['forever:server:restart']
}
tasks/register/watchForever.js Register your custom tasks (this file can be renamed to whatever you want)
module.exports = function(grunt) {
// Starts server
grunt.registerTask('start', [
'compileAssets',
'linkAssetsBuild',
'clean:build',
'copy:build',
'forever:server:start'
]);
// Restarts the server (if necessary) and waits for changes
grunt.registerTask('startWatch', [
'restart',
'watch:server'
]);
// Restarts server
grunt.registerTask('restart', [
'forever:server:restart'
]);
// Stops server
grunt.registerTask('stop', [
'forever:server:stop'
]);
};
With this you should be able to use
grunt startWatch
and make your server wait for changes to be restarted :>
Hope this helped!
Better you use
npm install -g nodemon
i am using this, and it will helps to improve my developing speed. no need to edit any files for this one!.
after installation
nodemon app.js
For anyone coming to this question now, it seems that this is no longer necessary - an application launched with sails lift will have a grunt watch task running, and code changes will be visible without a restart.
I didn't realise this was happening at first because there's nothing to indicate what's happening in the console, but it does seem to work without a restart (I'm using Sails 0.11)

Resources