Reputation: 717
How can I deploy NodeJS app with local dependencies to GAE???
My app has local dependencies in package.json, so it failed.
Thanks!
Upvotes: 2
Views: 547
Reputation: 3520
Thanks to @Hung Hoang for the question and their answer. Their answer solved my issue as well. I was motivated to write a solution that achieves the same result (and a few improvements) without using Gulp.
The following code assumes that you have a local package located at ../local
, and that the current working directory contains the Node.js application and the package.json
to be deployed to App Engine.
The overall idea is to copy the contents of ../local
to the Node.js app directory before deploying. This way, the local package code will be included as part of the code uploaded as part of the deploy, and the deploy will not result in an error. But, additionally, for this to work correctly the package.json
dependency entry for the ../local
package also needs to be updated.
There are three steps to the process (defined in Makefile format).
deploy: _predeploy _deploy _postdeploy
The pre-deploy step prepares files for deployment. See inline comments for details.
_predeploy:
# copy package to current directory
cp -r ../local tmp-local
# preserve original package.json,package-lock.json
cp package.json package.json.original
cp package-lock.json package-lock.json.original
# rewrite local dependency value in package.json (../local -> ./tmp-local)
sed -i '' 's/file:\.\.\/local/file:.\/tmp-local/g' package.json
# update package-lock.json corresondingly
npm i --package-lock-only
The deploy step does the actual deploy using the gcloud
command.
_deploy:
gcloud app deploy
Finally the post-deploy step cleans up files created during the pre-deploy step, and restores the original state of package.json
(such that ../local
can be used as usual for local development).
_postdeploy:
# undo package.json,package-lock.json changes
mv package.json.original package.json
mv package-lock.json.original package-lock.json
# remove copied package
rm -rf tmp-local
To run, execute make deploy
.
Upvotes: 1
Reputation: 717
No help came so I did it myself. Here's the solution for everyone has the same problem. Use gulp
to copy local resources into current directory.
const gulp = require('gulp');
const merge = require('merge-stream');
const runSequence = require('run-sequence');
const del = require('del');
const fs = require('fs');
const resolve = require('path').resolve;
let getPackageGlobs = (dir) => {
let paths = [
dir + '/**',
'!' + dir + '/node_modules/**',
'!' + dir + '/npm-debug.log',
'!' + dir + '/build',
];
try {
let data = fs.readFileSync(dir + '/.npmignore', {
encoding: 'utf-8',
});
paths = paths.concat(data.split("\n")
.filter((e) => e.length > 0)
.map((e) => dir + '/' + e)
.filter(fs.existsSync)
.map((e) => fs.lstatSync(e).isDirectory() ? '!' + e + '/**' : '!' + e));
} catch (err) { }
return paths;
};
gulp.task('build.clean', () => {
return del(__dirname + '/build');
});
gulp.task('build.copy', () => {
return gulp.src(getPackageGlobs(__dirname))
.pipe(gulp.dest('build'));
});
gulp.task('build.normalize', () => {
let packageJson = require('./build/package.json');
let tasks = [];
for (let name in packageJson.dependencies) {
for (let s of ['../', '~/', './', '/']) {
if (packageJson.dependencies[name].startsWith(s)) {
tasks.push(gulp
.src(getPackageGlobs(resolve(packageJson.dependencies[name])))
.pipe(gulp.dest('./build/local_modules/' + name)));
packageJson.dependencies[name] = './local_modules' + '/' + name;
break;
}
}
}
return new Promise((resolve, reject) => {
fs.writeFile('./build/package.json',
JSON.stringify(packageJson), (err) => {
if (err) {
reject(err);
} else {
resolve(merge(tasks));
}
});
});
});
gulp.task('build', (done) => {
runSequence('build.clean',
'build.copy',
'build.normalize',
done);
});
And run with gulp build && gcloud app deploy build/app.yaml
Upvotes: 2