diff --git a/.jshintignore b/.jshintignore
index 3efe38d3b66..089bd1f5ef1 100644
--- a/.jshintignore
+++ b/.jshintignore
@@ -2,5 +2,6 @@ appengine/kraken/public/components/**
appengine/sails/config/**
appengine/sails/tasks/**
appengine/sails/assets/**
+appengine/webpack/dist/**
**/node_modules/**
coverage/
\ No newline at end of file
diff --git a/appengine/webpack/.gitignore b/appengine/webpack/.gitignore
new file mode 100644
index 00000000000..77738287f0e
--- /dev/null
+++ b/appengine/webpack/.gitignore
@@ -0,0 +1 @@
+dist/
\ No newline at end of file
diff --git a/appengine/webpack/README.md b/appengine/webpack/README.md
new file mode 100644
index 00000000000..fb90d91468b
--- /dev/null
+++ b/appengine/webpack/README.md
@@ -0,0 +1,11 @@
+## Express.js + Webpack on Google App Engine
+
+> [Webpack][1] is a module bundler
+>
+> – webpack.github.io
+
+This sample application demonstrates how to use [Webpack][1] to bundle frontend
+code and then serve it with [Express.js][2] on Google App Engine.
+
+[1]: http://webpack.github.io/
+[2]: http://expressjs.com/
diff --git a/appengine/webpack/app.yaml b/appengine/webpack/app.yaml
new file mode 100644
index 00000000000..4268b2c650a
--- /dev/null
+++ b/appengine/webpack/app.yaml
@@ -0,0 +1,16 @@
+# Copyright 2015, 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.
+runtime: nodejs
+vm: true
+env_variables:
+ PORT: 8080
diff --git a/appengine/webpack/package.json b/appengine/webpack/package.json
new file mode 100644
index 00000000000..9779be2882b
--- /dev/null
+++ b/appengine/webpack/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "appengine-webpack",
+ "description": "An example of using Webpack with Node.js on Google App Engine.",
+ "version": "0.0.1",
+ "private": true,
+ "license": "Apache Version 2.0",
+ "engines": {
+ "node": "~4.2"
+ },
+ "scripts": {
+ "bundle": "webpack --config webpack.config.js",
+ "prestart": "npm run bundle",
+ "start": "node server.js",
+ "deploy": "gcloud preview app deploy app.yaml"
+ },
+ "dependencies": {
+ "body-parser": "^1.14.1",
+ "express": "^4.13.3",
+ "jade": "^1.11.0",
+ "webpack": "^1.12.6"
+ }
+}
diff --git a/appengine/webpack/public/app.js b/appengine/webpack/public/app.js
new file mode 100644
index 00000000000..d2b6deb24fc
--- /dev/null
+++ b/appengine/webpack/public/app.js
@@ -0,0 +1,19 @@
+// Copyright 2015, 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.
+
+/* global document:true */
+'use strict';
+
+var foo = require('./foo.js');
+
+document.getElementById('message').children[0].innerHTML = foo.name;
diff --git a/appengine/webpack/public/foo.js b/appengine/webpack/public/foo.js
new file mode 100644
index 00000000000..dcba093f4c2
--- /dev/null
+++ b/appengine/webpack/public/foo.js
@@ -0,0 +1,18 @@
+// Copyright 2015, 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';
+
+module.exports = {
+ name: 'foo'
+};
diff --git a/appengine/webpack/server.js b/appengine/webpack/server.js
new file mode 100644
index 00000000000..5ee6f77643f
--- /dev/null
+++ b/appengine/webpack/server.js
@@ -0,0 +1,46 @@
+// Copyright 2015, 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 bodyParser = require('body-parser');
+
+var app = express();
+
+// Setup view engine
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'jade');
+
+app.use(express.static(__dirname + '/dist'));
+
+// Parse form data
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({ extended: false }));
+
+app.get('/', function(req, res) {
+ res.render('index');
+});
+
+
+var server = app.listen(
+ process.env.PORT || 8080,
+ '0.0.0.0',
+ function () {
+ var address = server.address().address;
+ var port = server.address().port;
+ console.log('App listening at http://%s:%s', address, port);
+ console.log('Press Ctrl+C to quit.');
+ }
+);
diff --git a/appengine/webpack/views/index.jade b/appengine/webpack/views/index.jade
new file mode 100644
index 00000000000..0b4586018ce
--- /dev/null
+++ b/appengine/webpack/views/index.jade
@@ -0,0 +1,23 @@
+// Copyright 2015, 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
+ body
+ h1 Hello World!
+ p Express.js + Webpack on Google App Engine.
+ hr
+ p#message Loaded module via Webpack.
+ script(type='text/javascript', src='app.js')
diff --git a/appengine/webpack/webpack.config.js b/appengine/webpack/webpack.config.js
new file mode 100644
index 00000000000..f45f55d69d2
--- /dev/null
+++ b/appengine/webpack/webpack.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ entry: './public/app.js',
+ output: {
+ filename: './dist/app.js'
+ }
+};
diff --git a/test/appengine/all.test.js b/test/appengine/all.test.js
index bb13f2426f2..c458e86fde0 100644
--- a/test/appengine/all.test.js
+++ b/test/appengine/all.test.js
@@ -102,6 +102,13 @@ var sampleTests = [
args: ['server.js'],
msg: 'Hello World! Restify.js on Google App Engine.',
TRAVIS_NODE_VERSION: 'stable'
+ },
+ {
+ dir: 'webpack',
+ deploy: false,
+ cmd: 'node',
+ args: ['server.js'],
+ msg: 'Loaded module foo via Webpack.'
}
];