Skip to content
This repository was archived by the owner on Sep 10, 2022. It is now read-only.

Commit 0c8e6c7

Browse files
committed
Merge pull request #7 from addyosmani/static-page-server
Adding first version of the static page render
2 parents 6017932 + 42aa83d commit 0c8e6c7

33 files changed

+584
-326
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
src/third_party

.eslintrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
2
1515
],
1616
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
17-
"max-len": [2, 80, 2, {"ignoreUrls": true}],
17+
"max-len": [2, 80, 2],
1818
"new-cap": 2,
1919
"no-console": 0,
2020
"no-else-return": 2,
@@ -46,7 +46,7 @@
4646
"browser": true,
4747
"node": true
4848
},
49-
"extends": "eslint:recommended",
49+
"extends": "eslint:recommended",
5050
"globals": {
5151
"importScripts": true
5252
}

gulp-tasks/scripts.js

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,21 @@ var gulpif = require('gulp-if');
3030
var streamify = require('gulp-streamify');
3131
var replace = require('gulp-replace');
3232
var license = require('gulp-license');
33+
var sourcemaps = require('gulp-sourcemaps');
34+
var rename = require('gulp-rename');
3335

3436
gulp.task('scripts:watch', function() {
35-
gulp.watch(GLOBAL.config.src + '/**/*.es6.js', ['scripts:es6']);
37+
gulp.watch(GLOBAL.config.src + '/**/*.js', ['scripts']);
3638
});
3739

3840
// Takes a set of objects defining inputs of javascript files
3941
// to run through browserify and babelify
4042
function compileES6Bundles(browserifyBundles, minify) {
4143
browserifyBundles.forEach(function(bundle) {
4244
var browserifyBundle = browserify({
43-
entries: [bundle.srcPath],
44-
})
45-
.transform(babelify);
45+
entries: [bundle.srcPath]
46+
})
47+
.transform(babelify);
4648

4749
return browserifyBundle.bundle()
4850
.on('log', gutil.log.bind(gutil, 'Browserify Log'))
@@ -51,7 +53,7 @@ function compileES6Bundles(browserifyBundles, minify) {
5153
.pipe(replace(/@VERSION@/g, GLOBAL.config.version))
5254

5355
// If this is a production build - minify JS
54-
.pipe(gulpif(GLOBAL.config.env == 'prod', streamify(uglify())))
56+
.pipe(gulpif(GLOBAL.config.env === 'prod', streamify(uglify())))
5557
.pipe(license(GLOBAL.config.license, GLOBAL.config.licenseOptions))
5658
.pipe(gulp.dest(bundle.dest));
5759
});
@@ -82,17 +84,17 @@ function generateES6Bundles(srcPath) {
8284
browserifyBundles.push({
8385
srcPath: './' + filepath,
8486
outputFilename: outputFilename,
85-
dest: path.join(GLOBAL.config.dest, relativeDirectory),
87+
dest: path.join(GLOBAL.config.dest, relativeDirectory)
8688
});
8789
});
8890

8991
compileES6Bundles(browserifyBundles);
9092
}
9193

9294
gulp.task('scripts:eslint', function() {
93-
return gulp.src([GLOBAL.config.src + '/**/*.es6.js'])
95+
return gulp.src([GLOBAL.config.src + '/**/*.js'])
9496

95-
// eslint() attaches the lint output to the eslint property
97+
// eslint() attaches the lint output to the eslint property,
9698
// of the file object so it can be used by other modules.
9799
.pipe(eslint())
98100

@@ -105,12 +107,30 @@ gulp.task('scripts:eslint', function() {
105107
.pipe(eslint.failOnError());
106108
});
107109

108-
gulp.task('scripts:es6', ['scripts:eslint'], function(cb) {
110+
gulp.task('scripts:es6', function(cb) {
109111
generateES6Bundles(GLOBAL.config.src);
110112

111113
cb();
112114
});
113115

116+
gulp.task('scripts:es5', function() {
117+
return gulp.src([GLOBAL.config.src + '/**/*.es5.js'])
118+
.pipe(gulpif(GLOBAL.config.env !== 'prod', sourcemaps.init()))
119+
120+
// Remove the .es5 from the end of the file name using gulp-rename
121+
.pipe(rename(function(filePath) {
122+
var fileExtensionLength = '.es5'.length;
123+
filePath.basename = filePath.basename.substr(
124+
0, filePath.basename.length - fileExtensionLength);
125+
}))
126+
127+
.pipe(replace(/@VERSION@/g, GLOBAL.config.version))
128+
.pipe(gulpif(GLOBAL.config.env === 'prod', uglify()))
129+
.pipe(license(GLOBAL.config.license, GLOBAL.config.licenseOptions))
130+
.pipe(gulpif(GLOBAL.config.env !== 'prod', sourcemaps.write()))
131+
.pipe(gulp.dest(GLOBAL.config.dest));
132+
});
133+
114134
// Delete any files currently in the scripts destination path
115135
gulp.task('scripts:clean', function(cb) {
116136
del([GLOBAL.config.dest + '/**/*.js'], {dot: true})
@@ -121,8 +141,14 @@ gulp.task('scripts:clean', function(cb) {
121141

122142
gulp.task('scripts', function(cb) {
123143
runSequence(
124-
'scripts:clean',
125-
['scripts:es6'],
144+
[
145+
'scripts:clean',
146+
'scripts:eslint'
147+
],
148+
[
149+
'scripts:es6',
150+
'scripts:es5'
151+
],
126152
cb
127153
);
128154
});

gulp-tasks/styles.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var AUTOPREFIXER_BROWSERS = [
3434
'opera >= 23',
3535
'ios >= 7',
3636
'android >= 4.4',
37-
'bb >= 10',
37+
'bb >= 10'
3838
];
3939

4040
gulp.task('styles:watch', function() {
@@ -53,12 +53,12 @@ gulp.task('styles:sass', function() {
5353
var stream = gulp.src(GLOBAL.config.src + '/**/*.scss')
5454

5555
// Only create sourcemaps for dev
56-
.pipe(gulpif(GLOBAL.config.env != 'prod', sourcemaps.init()))
56+
.pipe(gulpif(GLOBAL.config.env !== 'prod', sourcemaps.init()))
5757
.pipe(sass())
5858
.pipe(autoprefixer(AUTOPREFIXER_BROWSERS))
59-
.pipe(minifyCSS())
59+
.pipe(gulpif(GLOBAL.config.env === 'prod', minifyCSS()))
6060
.pipe(license(GLOBAL.config.license, GLOBAL.config.licenseOptions))
61-
.pipe(gulpif(GLOBAL.config.env != 'prod', sourcemaps.write()))
61+
.pipe(gulpif(GLOBAL.config.env !== 'prod', sourcemaps.write()))
6262
.pipe(gulp.dest(GLOBAL.config.dest));
6363

6464
return stream;

gulp-tasks/third_party.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ gulp.task('third_party:watch', function() {
2323

2424
gulp.task('third_party', function() {
2525
gulp.src(GLOBAL.config.src + '/third_party/**/*.*')
26-
.pipe(gulp.dest(GLOBAL.config.dest + '/third_party'))
26+
.pipe(gulp.dest(GLOBAL.config.dest + '/third_party'));
2727
});

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "app-shell",
3-
"version": "0.1.120",
3+
"version": "0.1.150",
44
"private": true,
55
"license": "Apache",
66
"engines": {
@@ -10,6 +10,8 @@
1010
"babelify": "^6.3.0",
1111
"browserify": "^11.2.0",
1212
"del": "^2.0.2",
13+
"express": "^4.13.3",
14+
"express-handlebars": "^2.0.1",
1315
"glob": "^5.0.15",
1416
"gulp": "^3.9.0",
1517
"gulp-autoprefixer": "^3.1.0",
@@ -20,6 +22,7 @@
2022
"gulp-license": "^1.0.0",
2123
"gulp-minify-css": "^1.2.1",
2224
"gulp-minify-html": "^1.0.4",
25+
"gulp-rename": "^1.2.2",
2326
"gulp-replace": "^0.5.4",
2427
"gulp-sass": "^2.0.4",
2528
"gulp-sourcemaps": "^1.6.0",

server/app.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
/**
4+
*
5+
* The structure of this node server is the following:
6+
* 1.) server-controller starts an express server which defines the static
7+
* content, port number and sets up handle bars to use the views and layouts
8+
* 2.) URLs are then routed by defining a url and calling addEndpoint(). On
9+
* requests to a matching url the onRequest() method is called in the
10+
* passed in controller (i.e. StaticPageController)
11+
*
12+
*/
13+
14+
var serverController = require('./controllers/server-controller');
15+
var StaticPageController = require('./controllers/static-page-controller');
16+
17+
serverController.addEndpoint('/*', new StaticPageController());
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
var path = require('path');
2+
var express = require('express');
3+
var exphbs = require('express-handlebars');
4+
5+
function ServerController() {
6+
var expressApp = express();
7+
var expressServer = this.setUpServer(expressApp);
8+
9+
this.getExpressApp = function() {
10+
return expressApp;
11+
};
12+
13+
this.getExpressServer = function() {
14+
return expressServer;
15+
};
16+
}
17+
18+
ServerController.prototype.setUpServer = function(app) {
19+
// Set up the use of handle bars and set the path for views and layouts
20+
app.set('views', path.join(__dirname, '/../views'));
21+
app.engine('handlebars', exphbs({
22+
defaultLayout: 'default',
23+
layoutsDir: path.join(__dirname, '/../layouts')
24+
}));
25+
app.set('view engine', 'handlebars');
26+
27+
// Define static assets path - i.e. styles, scripts etc.
28+
app.use('/',
29+
express.static(path.join(__dirname + '/../../dist/')));
30+
31+
console.log('Starting server on 3123');
32+
return app.listen('3123');
33+
};
34+
35+
ServerController.prototype.addEndpoint = function(endpoint, controller) {
36+
// Add the endpoint and call the onRequest method when a request is made
37+
this.getExpressApp().get(endpoint, function(req, res) {
38+
controller.onRequest(req, res);
39+
});
40+
};
41+
42+
module.exports = new ServerController();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
'use strict';
2+
3+
var fs = require('fs');
4+
var path = require('path');
5+
6+
function StaticPageController() {
7+
8+
}
9+
10+
function prepareData(config) {
11+
// Concat inline styles for document <head>
12+
var flattenedStyles = '';
13+
var pathPrefix = '/../../dist/';
14+
config.inlineStyles.forEach(function(file) {
15+
flattenedStyles += fs.readFileSync(path.resolve(__dirname) +
16+
pathPrefix + file);
17+
});
18+
19+
// Replace array with flattened string of content
20+
config.inlineStyles = flattenedStyles;
21+
return config;
22+
}
23+
24+
// This method looks at the request path and renders the appropriate handlebars
25+
// template
26+
StaticPageController.prototype.onRequest = function(req, res) {
27+
switch (req.path) {
28+
case '/':
29+
res.render('index', prepareData({
30+
inlineStyles: ['/styles/core.css'],
31+
remoteStyles: [],
32+
inlineScripts: [],
33+
remoteScripts: ['/scripts/static-page.js']
34+
}));
35+
break;
36+
case '/url-1':
37+
res.render('url-1', prepareData({
38+
inlineStyles: ['/styles/core.css'],
39+
remoteStyles: [],
40+
inlineScripts: [],
41+
remoteScripts: ['/scripts/static-page.js']
42+
}));
43+
break;
44+
case '/url-2':
45+
res.render('url-2', prepareData({
46+
inlineStyles: ['/styles/core.css'],
47+
remoteStyles: [],
48+
inlineScripts: [],
49+
remoteScripts: ['/scripts/static-page.js']
50+
}));
51+
break;
52+
default:
53+
res.status(404).send();
54+
break;
55+
}
56+
};
57+
58+
module.exports = StaticPageController;

server/layouts/default.handlebars

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>App Shell</title>
6+
7+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8+
<meta name="viewport" content="width=device-width, initial-scale=1">
9+
<meta id="theme-color" name="theme-color" content="#4527A0">
10+
11+
<link rel="manifest" href="/manifest.json">
12+
<link rel="icon" href="/images/chrome-touch-icon-192x192.png" sizes="192x192" type="image/png">
13+
14+
<style type="text/css">{{{inlineStyles}}}</style>
15+
</head>
16+
<body>
17+
18+
<header class="header">
19+
<button tabindex="-1" class="header__menu js-toggle-menu">
20+
Toggle nav menu
21+
</button>
22+
23+
<h1 class="header__title">App shell</h1>
24+
</header>
25+
26+
<main class="main js-main" aria-role="main">
27+
{{{body}}}
28+
</main>
29+
30+
<section class="side-nav js-side-nav">
31+
<div class="side-nav__content js-side-nav-content">
32+
<div class="side-nav__header">
33+
<h1 class="side-nav__title">App shell</h1>
34+
</div>
35+
36+
<div class="side-nav__body">
37+
<a tabindex="-1" class="side-nav__blog-post" href="/">Index</a>
38+
<a tabindex="-1" class="side-nav__blog-post" href="/url-1">URL 1</a>
39+
<a tabindex="-1" class="side-nav__blog-post" href="/url-2">URL 2</a>
40+
</div>
41+
42+
<div class="side-nav__version">Version @VERSION@</div>
43+
</div>
44+
</section>
45+
46+
{{#each remoteScripts}}
47+
<script src="{{this}}" async></script>
48+
{{~/each}}
49+
</body>
50+
</html>

0 commit comments

Comments
 (0)