This repository has been archived by the owner on Nov 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
gulpfile.js
164 lines (148 loc) · 4.93 KB
/
gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
const gulp = require('gulp');
const less = require('gulp-less');
const cssnano = require('cssnano');
const postCSS = require('gulp-postcss');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const through = require('through2');
const ts = require('gulp-typescript');
const path = require('path');
const sourcemaps = require('gulp-sourcemaps');
const merge = require('merge2');
const jsPath = './src/client/';
const dist = './public/';
/**
* @see https://github.com/gulp-sourcemaps/gulp-sourcemaps
*/
const sourceMapConfig = {
sourceMappingURL: file => '/js/maps/' + file.relative + '.map'
};
/**
* TypeScript configuration should set noEmitOnError=true to keep incremental
* compilation from building and caching bad bundles.
*
* @see https://github.com/ivogabe/gulp-typescript
*/
const tsConfig = ts.createProject('tsconfig.browser.json');
// https://github.com/plus3network/gulp-less
// https://github.com/jonathanepollack/gulp-minify-css
// https://github.com/jakubpawlowicz/clean-css/blob/master/README.md
const buildCSS = () =>
merge(
gulp
.src(lessPath(['map', 'mapbox', 'admin']))
.pipe(less())
.on('error', handleError),
merge(
// combine fonts with main styles
gulp
.src(lessPath(['ti']))
.pipe(less())
.on('error', handleError),
gulp.src(dist + 'fonts/webfont.css')
).pipe(concat('ti.css'))
)
.pipe(less())
.on('error', handleError)
.pipe(postCSS([cssnano({ discardUnused: false })]))
.on('error', handleError)
.pipe(gulp.dest(dist + 'css'));
// https://github.com/gulp-sourcemaps/gulp-sourcemaps
const buildJS = () =>
merge(tsConfig.src().pipe(tsConfig()))
.pipe(
bundle('post', 'static-map', 'lazy-load').as('post', {
keep: ['static-map']
})
)
.pipe(bundle('mapbox', 'util').as('mapbox', { keep: 'util' }))
// responsive script is on every page except map
.pipe(bundle('responsive', 'util').as('responsive'))
.pipe(bundle('static-map').as('category'))
.pipe(sourcemaps.init())
.pipe(uglify())
.on('error', handleError)
.pipe(sourcemaps.write('maps', sourceMapConfig))
.pipe(gulp.dest(dist + 'js'));
gulp.task('js', buildJS);
gulp.task('css', buildCSS);
// act on changes
gulp.task('watch', () => {
gulp.watch('./src/less/*.less', buildCSS);
gulp.watch('./src/client/*.?s', buildJS);
});
//#region Helpers
/**
* @param {string[]} names
* @returns {string[]}
*/
const lessPath = names => names.map(n => './src/less/' + n + '.less');
/**
* Handle error so file watcher can continue
* @param {object} error
* @see http://stackoverflow.com/questions/23971388/prevent-errors-from-breaking-crashing-gulp-watch
*/
function handleError(error) {
console.error(error);
this.emit('end');
}
/**
* Bundle list of Javascript files as the target file. Source files are removed
* from the stream and replaced by the target file unless listed in
* options.keep.
*
* The TypeScript compiler should be configured not to emit if there are errors
* otherwise this method caches bad files.
*
* Based on gulp-concat
* @param {string[]} files Names of files to merge into single bundle
* @see https://github.com/contra/gulp-concat/blob/master/index.js
*/
const bundle = (...files) => ({
as(target, options = {}) {
const ext = '.js';
// merged content
let content = [];
// files to keep in the stream after bundling
let keep = [];
// vinyl file used as template to create output file
let template = null;
if (options.keep) {
keep = Array.isArray(options.keep) ? options.keep : [options.keep];
}
// prevent e.g. "post" from matching post-menu.js
files = files.map(f => f + ext);
keep = keep.map(k => k + ext);
target += ext;
function transform(file, enc, cb) {
const name = file.basename ? file.basename : file.relative;
if (files.indexOf(name) >= 0) {
content.push(file.contents);
// use first file as template
if (template == null) {
template = file;
}
// if not keeping file then empty callback removes it from stream
if (keep.length == 0 || keep.indexOf(name) == -1) {
cb();
return;
}
}
// any file returned in callback is kept in stream
cb(null, file);
}
// create merged file and place in stream
// `this` refers to current stream (array of vinyl files)
function finish(cb) {
if (content.length == files.length) {
const merged = template.clone({ contents: false });
merged.path = path.join(merged.base, target);
merged.contents = Buffer.concat(content);
this.push(merged);
}
cb();
}
return through.obj(transform, finish);
}
});
//#endregion