diff --git a/README.md b/README.md index 910d937994..1ed4673603 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ __Tools__ - gcloud-node - [Source code][gcloud_1] | [Documentation][gcloud_2] - Bower - [Source code][bower_1] | [App Engine Tutorial][bower_2] | [Documentation][bower_3] - Grunt - [Source code][grunt_1] | [App Engine Tutorial][grunt_2] | [Live demo][grunt_3] | [Documentation][grunt_4] +- Gulp - [Source code][gulp_1] | [Documentation][gulp_2] - Mailgun - [Source code][mailgun_1] | [App Engine Tutorial][mailgun_2] | [Documentation][mailgun_3] - Sendgrid - [Source code][sendgrid_1] | [App Engine Tutorial][sendgrid_2] | [Documentation][sendgrid_3] - Twilio - [Source code][twilio_1] @@ -228,6 +229,9 @@ See [LICENSE](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/ma [bower_2]: https://cloud.google.com/nodejs/resources/tools/bower [bower_3]: http://bower.io/ +[gulp_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/appengine/gulp +[gulp_2]: http://gulpjs.com/ + [grunt_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/appengine/grunt [grunt_2]: https://cloud.google.com/nodejs/resources/tools/grunt [grunt_3]: http://grunt-dot-nodejs-docs-samples.appspot.com diff --git a/appengine/gulp/.gitignore b/appengine/gulp/.gitignore new file mode 100644 index 0000000000..8178a2b481 --- /dev/null +++ b/appengine/gulp/.gitignore @@ -0,0 +1 @@ +src/public/stylesheets/style.min.css \ No newline at end of file diff --git a/appengine/gulp/.jshintrc b/appengine/gulp/.jshintrc new file mode 100644 index 0000000000..feb092894f --- /dev/null +++ b/appengine/gulp/.jshintrc @@ -0,0 +1,21 @@ +{ + "node": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "eqeqeq": true, + "eqnull": true, + "immed": true, + "indent": 2, + "latedef": "nofunc", + "newcap": true, + "nonew": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": false, + "trailing": true, + "sub": true, + "maxlen": 80 +} diff --git a/appengine/gulp/Gulpfile.js b/appengine/gulp/Gulpfile.js new file mode 100644 index 0000000000..c9af465c4b --- /dev/null +++ b/appengine/gulp/Gulpfile.js @@ -0,0 +1,27 @@ +var gulp = require('gulp'); +var jshint = require('gulp-jshint'); +var cssnano = require('gulp-cssnano'); + +// Lint Task +gulp.task('lint', function() { + return gulp.src(['Gulpfile.js', 'src/**/*.js']) + .pipe(jshint()) + .pipe(jshint.reporter('default')); +}); + +// Minify CSS +gulp.task('styles', function() { + return gulp.src('src/public/stylesheets/*.css') + .pipe(cssnano()) + .pipe(gulp.dest('src/public/stylesheets')); +}); + +// Watch Files For Changes +gulp.task('watch', function() { + gulp.watch('src/**/*.js', ['lint', 'scripts']); + gulp.watch('src/public/stylesheets/*.css', ['styles']); +}); + + +gulp.task('build', ['lint', 'styles']); +gulp.task('default', ['lint', 'styles', 'watch']); diff --git a/appengine/gulp/README.md b/appengine/gulp/README.md new file mode 100644 index 0000000000..bfbe486188 --- /dev/null +++ b/appengine/gulp/README.md @@ -0,0 +1,32 @@ +## Gulp.js on Google App Engine + +> [Gulp][1]: The JavaScript Task Runner. + +This sample demonstrates how to use [Gulp](http://gulpjs.com/) on +[Google App Engine Managed VMs](https://cloud.google.com/appengine/docs/managed-vms/). + +For more information about getting started with Gulp, see the +[Getting Started with Gulp Guide](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md). + +## Setup +Add the necessary modules +```sh +$ npm install +``` + +Run gulp build to minify css and lint javascript files +```sh +$ npm run build +``` + +## Running locally +Refer to the [appengine/README.md](../README.md) file for instructions on +running and deploying. + + +Run gulp, gulp default watches javascript and css files in src. Run npm start to start the express server. + +```sh +$ gulp +$ npm start +``` diff --git a/appengine/gulp/app.yaml b/appengine/gulp/app.yaml new file mode 100644 index 0000000000..c1c22cd8cb --- /dev/null +++ b/appengine/gulp/app.yaml @@ -0,0 +1,20 @@ +# Copyright 2015-2016, Google, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START app_yaml] +runtime: nodejs +vm: true + +skip_files: + - ^(.*/)?.*/node_modules/.*$ +# [END app_yaml] diff --git a/appengine/gulp/package.json b/appengine/gulp/package.json new file mode 100644 index 0000000000..d085379f0f --- /dev/null +++ b/appengine/gulp/package.json @@ -0,0 +1,31 @@ +{ + "name": "appengine-gulpjs", + "description": "An example of running Gulp.js on Google App Engine.", + "version": "0.0.1", + "private": true, + "license": "Apache Version 2.0", + "author": "Google Inc.", + "engines": { + "node": "~4.2" + }, + "scripts": { + "start": "node ./src/bin/www", + "postinstall": "gulp build", + "deploy": "gcloud preview app deploy" + }, + "dependencies": { + "body-parser": "^1.14.2", + "cookie-parser": "^1.4.1", + "debug": "^2.2.0", + "express": "^4.13.4", + "jade": "^1.11.0", + "jshint": "^2.9.1", + "gulp": "^3.9.1", + "gulp-cssnano": "^2.1.1", + "gulp-jshint": "^2.0.0", + "morgan": "^1.6.1", + "serve-favicon": "^2.3.0" + }, + "devDependencies": { + } +} diff --git a/appengine/gulp/src/app.js b/appengine/gulp/src/app.js new file mode 100644 index 0000000000..9b8ea73318 --- /dev/null +++ b/appengine/gulp/src/app.js @@ -0,0 +1,72 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var express = require('express'); +var path = require('path'); +var logger = require('morgan'); +var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); + +var routes = require('./routes/index'); +var users = require('./routes/users'); + +var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); + +app.use(logger('dev')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.use('/', routes); +app.use('/users', users); + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handlers + +// development error handler +// will print stacktrace +if (app.get('env') === 'development') { + app.use(function(err, req, res) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: err + }); + }); +} + +// production error handler +// no stacktraces leaked to user +app.use(function(err, req, res) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: {} + }); +}); + + +module.exports = app; diff --git a/appengine/gulp/src/bin/www b/appengine/gulp/src/bin/www new file mode 100644 index 0000000000..7d9036ee45 --- /dev/null +++ b/appengine/gulp/src/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +'use strict'; + +// [START server] + +/** + * Module dependencies. + */ +var app = require('../app'); +var debug = require('debug')('express:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ +var port = normalizePort(process.env.PORT || 8080); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +// [END server] + +/** + * Normalize a port into a number, string, or false. + */ +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/appengine/gulp/src/public/stylesheets/style.css b/appengine/gulp/src/public/stylesheets/style.css new file mode 100644 index 0000000000..33141687dc --- /dev/null +++ b/appengine/gulp/src/public/stylesheets/style.css @@ -0,0 +1 @@ +body{padding:50px;font:14px Lucida Grande,Helvetica,Arial,sans-serif}a{color:#00b7ff}h1{color:#ff0} \ No newline at end of file diff --git a/appengine/gulp/src/routes/index.js b/appengine/gulp/src/routes/index.js new file mode 100644 index 0000000000..4bd9407c78 --- /dev/null +++ b/appengine/gulp/src/routes/index.js @@ -0,0 +1,27 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var express = require('express'); +var router = express.Router(); + +// [START hello_world] +router.get('/', function(req, res) { + res.render('index', { + title: 'Hello World! Express.js + Grunt.js on Google App Engine.' + }); +}); +// [END hello_world] + +module.exports = router; diff --git a/appengine/gulp/src/routes/users.js b/appengine/gulp/src/routes/users.js new file mode 100644 index 0000000000..40172d5515 --- /dev/null +++ b/appengine/gulp/src/routes/users.js @@ -0,0 +1,24 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +router.get('/', function(req, res, next) { + res.send('respond with a resource'); +}); + +module.exports = router; diff --git a/appengine/gulp/src/views/error.jade b/appengine/gulp/src/views/error.jade new file mode 100644 index 0000000000..28c938f622 --- /dev/null +++ b/appengine/gulp/src/views/error.jade @@ -0,0 +1,19 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extends layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/appengine/gulp/src/views/index.jade b/appengine/gulp/src/views/index.jade new file mode 100644 index 0000000000..fb89323e39 --- /dev/null +++ b/appengine/gulp/src/views/index.jade @@ -0,0 +1,18 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extends layout + +block content + h1= title + p Welcome to #{title} diff --git a/appengine/gulp/src/views/layout.jade b/appengine/gulp/src/views/layout.jade new file mode 100644 index 0000000000..2d30f50f53 --- /dev/null +++ b/appengine/gulp/src/views/layout.jade @@ -0,0 +1,20 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.min.css') + body + block content \ No newline at end of file