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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
/* To build bundles...
1. npm run uf-bundle-build
2. npm run uf-bundle
3. npm run uf-bundle-clean
To get frontend vendor packages via bower
1. npm run uf-assets-install
To clean frontend vendor assets
1. npm run uf-assets-clean
*/
"use strict";
const gulp = require('gulp');
const del = require('del');
const fs = require('fs');
const shell = require('shelljs');
const plugins = require('gulp-load-plugins')();
const sprinklesDir = '../app/sprinkles/';
const sprinklesSchemaPath = '../app/sprinkles.json';
// The Sprinkle load order from sprinkles.json
const sprinkles = ['core'].concat(require(`${sprinklesSchemaPath}`)['base']);
// The directory where the bundle task should place compiled assets.
// The names of assets in bundle.result.json will be specified relative to this path.
const publicAssetsDir = '../public/assets/';
// name of the bundle file
const bundleFile = 'asset-bundles.json';
// Compiled bundle config file
const bundleConfigFile = `./${bundleFile}`;
// Destination directory for vendor assets
const vendorAssetsDir = './assets/vendor';
/**
* Vendor asset task
*/
// Gulp task to install vendor packages via bower
gulp.task('bower-install', () => {
"use strict";
shell.cd(`${sprinklesDir}`);
sprinkles.forEach((sprinkle) => {
if (fs.existsSync(`${sprinkle}/bower.json`)) {
console.log(`bower.json found in '${sprinkle}' Sprinkle, installing assets.`);
shell.cd(`${sprinkle}`);
shell.exec(`bower install --config.directory=${vendorAssetsDir}`);
shell.cd(`../`);
}
});
return true;
});
/**
* Bundling tasks
*/
// Executes bundleing tasks according to bundle.config.json files in each Sprinkle, as per Sprinkle load order.
// Respects bundle collision rules.
gulp.task('bundle-build', () => {
"use strict";
let copy = require('recursive-copy');
let merge = require('merge-array-object');
let cleanup = (e) => {
"use strict";
// Delete temporary directory if exists
fs.rmdirSync("./temp");
// Delete created bundle.config.json file
fs.unlinkSync(bundleConfigFile);
// Propagate error
throw e;
};
let config = {
bundle: {},
copy: []
};
sprinkles.forEach((sprinkle) => {
"use strict";
let location = `${sprinklesDir}/${sprinkle}/`;
if (fs.existsSync(`${location}${bundleFile}`)) {
let currentConfig = require(`${location}${bundleFile}`);
// Add bundles to config, respecting collision rules.
for (let bundleName in currentConfig.bundle) {
// If bundle already defined, handle as per collision rules.
if (bundleName in config.bundle) {
let onCollision = 'replace';
try {
onCollision = (typeof currentConfig.bundle[bundleName].options.sprinkle.onCollision !== 'undefined' ? currentConfig.bundle[bundleName].options.sprinkle.onCollision : 'replace');
}
catch (e) {
}
switch (onCollision) {
case 'replace':
config.bundle[bundleName] = currentConfig.bundle[bundleName];
break;
case 'merge':
// If using this collision rule, keep in mind any bundling options will also be merged.
// Inspect the produced 'bundle.config.json' file in the 'build' folder to ensure options are correct.
config.bundle[bundleName] = merge(currentConfig.bundle[bundleName], config.bundle[bundleName]);
break;
case 'ignore':
// Do nothing. This simply exists to prevent falling through to error catchment.
break;
case 'error':
cleanup(`The bundle '${bundleName}' in the Sprinkle '${sprinkle}' has been previously defined, and the bundle's 'onCollision' property is set to 'error'.`);
default:
cleanup(`Unexpected input '${onCollision}' for 'onCollision' for the bundle '${bundleName}' in the Sprinkle '${sprinkle}'.`);
}
}
// Otherwise, just add.
else {
config.bundle[bundleName] = currentConfig.bundle[bundleName];
}
}
// Add/merge copy files to config
if ('copy' in currentConfig) {
config.copy = new Set(config.copy, currentConfig.copy);
}
}
});
// Save bundle rules to bundle.config.json
fs.writeFileSync(bundleConfigFile, JSON.stringify(config));
// Copy all assets in order of Sprinkle load order.
let sprinkleAssets = []
sprinkles.forEach((sprinkle) => {
"use strict";
sprinkleAssets.push(`../app/sprinkles/${sprinkle}/assets/**/*`);
});
// Gulp v4 src respects order, until it is released, use this alternative.
return plugins.srcOrderedGlobs(sprinkleAssets)
.pipe(plugins.copy('../public/assets/', {prefix: 5}));// And gulp.dest doesn't give us the control needed.
});
// Execute gulp-bundle-assets
gulp.task('bundle', () => {
"use strict";
return gulp.src(bundleConfigFile)
.pipe(plugins.ufBundleAssets({
base: publicAssetsDir
}))
.pipe(plugins.ufBundleAssets.results({
dest: './'
}))
.pipe(gulp.dest(publicAssetsDir));
});
/**
* Clean up tasks
*/
gulp.task('public-clean', () => {
"use strict";
return del(publicAssetsDir, { force: true });
});
// Clean up temporary bundling files
gulp.task('bundle-clean', () => {
"use strict";
return del(bundleConfigFile, { force: true });
});
// Deletes assets fetched by bower-install
gulp.task('bower-clean', () => {
"use strict";
return del(`${sprinklesDir}/*/assets/vendor`, { force: true });
});
// Deletes all generated, or acquired files.
gulp.task('clean', () => {
"use strict";
del(publicAssetsDir, { force: true});
del(bundleConfigFile, { force: true });
del(`${sprinklesDir}/*/assets/vendor`, { force: true });
return true;
})
|