1 |
|
2 |
|
3 |
|
4 | 'use strict';
|
5 |
|
6 |
|
7 | const { exec } = require('child_process');
|
8 | const corejs = require('core-js-builder');
|
9 | const gulp = require('gulp');
|
10 | const cache = require('gulp-cached');
|
11 | const eslint = require('gulp-eslint');
|
12 | const gulpif = require('gulp-if');
|
13 | const lec = require('gulp-line-ending-corrector');
|
14 | const uglify = require('gulp-uglify');
|
15 | const cloneDeep = require('lodash.clonedeep');
|
16 | const modernizr = require('modernizr');
|
17 | const pluralize = require('pluralize');
|
18 | const fsp = require('@absolunet/fsp');
|
19 | const fss = require('@absolunet/fss');
|
20 | const include = require('@absolunet/gulp-include');
|
21 | const { terminal } = require('@absolunet/terminal');
|
22 | const env = require('~/helpers/env');
|
23 | const flow = require('~/helpers/flow');
|
24 | const paths = require('~/helpers/paths');
|
25 | const toolbox = require('~/helpers/toolbox');
|
26 | const util = require('~/helpers/util');
|
27 |
|
28 |
|
29 | module.exports = () => {
|
30 |
|
31 |
|
32 | flow.createTask('scripts-lint', ({ taskName }) => {
|
33 | return gulp.src(paths.files.scriptsLint)
|
34 |
|
35 |
|
36 | .pipe(cache('scripts', { optimizeMemory: true }))
|
37 |
|
38 | .pipe(gulpif(env.isWindows, lec()))
|
39 |
|
40 | .pipe(eslint())
|
41 |
|
42 | .pipe(eslint.results((files) => {
|
43 | let hasErrors = false;
|
44 |
|
45 | files.forEach((file) => {
|
46 | if (file.errorCount || file.warningCount) {
|
47 | delete cache.caches.scripts[file.filePath];
|
48 | hasErrors = true;
|
49 | }
|
50 | });
|
51 |
|
52 | if (!hasErrors) {
|
53 | toolbox.log(taskName, `${pluralize('file', files.length, true)} linted`);
|
54 | }
|
55 | }))
|
56 |
|
57 | .pipe(eslint.format('stylish'))
|
58 |
|
59 | .pipe(eslint.failAfterError())
|
60 | ;
|
61 | });
|
62 |
|
63 |
|
64 |
|
65 | flow.createTask('scripts-constants', ({ taskName }) => {
|
66 | const streams = [];
|
67 |
|
68 | for (const name of Object.keys(env.bundles)) {
|
69 | const data = {
|
70 | [env.id]: env.workflowConfig.version,
|
71 | project: env.packageConfig.name,
|
72 | bundle: name,
|
73 | konstan: util.parseKonstan('scripts', name, env.bundles[name].output)
|
74 | };
|
75 |
|
76 |
|
77 | streams.push(
|
78 | toolbox.vinylStream(paths.filename.konstanScripts, `var konstan = ${JSON.stringify(data, null, '\t')};`)
|
79 | .pipe(toolbox.plumber())
|
80 | .pipe(gulp.dest(`${paths.directory.cacheScripts}/${name}`))
|
81 | );
|
82 |
|
83 | }
|
84 |
|
85 | return toolbox.mergeStreams(streams).on('finish', () => {
|
86 | flow.skipOnWatch(taskName);
|
87 | toolbox.log(taskName, `${pluralize('file', streams.length, true)} generated`);
|
88 | });
|
89 |
|
90 | });
|
91 |
|
92 |
|
93 |
|
94 | flow.createTask('scripts-vendors', ({ taskName }) => {
|
95 |
|
96 | const log = (name, file) => {
|
97 | toolbox.log(taskName, `${name} built`, toolbox.filesize(file));
|
98 | };
|
99 |
|
100 | return toolbox.fakeStream((callback) => {
|
101 |
|
102 | const modernizrBuild = new Promise((resolve) => {
|
103 | modernizr.build(fss.readYaml(paths.config.modernizr), (result) => {
|
104 | const file = `${paths.directory.cacheScripts}/${paths.filename.modernizr}.${paths.extension.scripts}`;
|
105 | fsp.ensureFile(file).then(() => {
|
106 | fss.writeFile(file, result);
|
107 | log('Modernizr', file);
|
108 | resolve();
|
109 | });
|
110 | });
|
111 | });
|
112 |
|
113 | const lodashBuild = new Promise((resolve) => {
|
114 | const options = util.parseLodash();
|
115 | const file = `${paths.directory.cacheScripts}/${paths.filename.lodash}.${paths.extension.scripts}`;
|
116 |
|
117 | exec(`node ${paths.config.lodashBin} ${options} --development --output ${file}`, (error, stdout, stderr) => {
|
118 | if (error !== null) {
|
119 | terminal.error(stderr);
|
120 | }
|
121 | log('Lodash', file);
|
122 | resolve();
|
123 | });
|
124 | });
|
125 |
|
126 | const polyfillBuild = new Promise((resolve) => {
|
127 | const file = `${paths.directory.cacheScripts}/${paths.filename.polyfill}.${paths.extension.scripts}`;
|
128 |
|
129 | corejs({
|
130 | modules: ['web', 'es'],
|
131 | targets: env.configRaw.polyfill,
|
132 | filename: file
|
133 | }).then(() => {
|
134 | fsp.appendFile(file, fss.readFile(paths.config.regeneratorRuntime, 'utf8')).then(() => {
|
135 | log('core-js polyfill', file);
|
136 | resolve();
|
137 | });
|
138 | });
|
139 | });
|
140 |
|
141 |
|
142 | Promise.all([modernizrBuild, lodashBuild, polyfillBuild]).then(() => {
|
143 | flow.skipOnWatch(taskName);
|
144 | callback();
|
145 | });
|
146 |
|
147 | });
|
148 |
|
149 | });
|
150 |
|
151 |
|
152 |
|
153 | flow.createTask('scripts-compile', ({ taskName }) => {
|
154 | const streams = [];
|
155 |
|
156 | for (const name of Object.keys(env.bundles)) {
|
157 | const bundle = env.bundles[name];
|
158 |
|
159 |
|
160 | const babelExtraAllowed = util.getBabelAllowedRules(bundle.scripts.allowBabel);
|
161 |
|
162 |
|
163 | for (const collection of Object.keys(bundle.scripts.collections)) {
|
164 | const list = cloneDeep(bundle.scripts.collections[collection]);
|
165 |
|
166 |
|
167 | const replacements = {
|
168 | konstan: `${paths.folder.cacheScripts}/${name}/${paths.filename.konstan}`,
|
169 | lodash: `${paths.folder.cacheScripts}/${paths.filename.lodash}`,
|
170 | modernizr: `${paths.folder.cacheScripts}/${paths.filename.modernizr}`,
|
171 | polyfill: `${paths.folder.cacheScripts}/${paths.filename.polyfill}`
|
172 | };
|
173 | for (const title of Object.keys(replacements)) {
|
174 | const pos = list.indexOf(`~${title}`);
|
175 | if (pos !== -1) {
|
176 | list[pos] = replacements[title];
|
177 | }
|
178 | }
|
179 |
|
180 |
|
181 | list.forEach((file, i) => {
|
182 | list[i] = `//= require ${file}`;
|
183 | });
|
184 |
|
185 | const toMinify = (bundle.scripts.options.minify && !env.watching) || env.production;
|
186 | const filename = `${collection}.${paths.extension.scripts}`;
|
187 | const destination = `${bundle.output.build}/${paths.build.scripts}`;
|
188 | const source = `${util.getGeneratedBanner(name)} (function(global, undefined) { \n\t${list.join('\n')}\n })(typeof window !== 'undefined' ? window : this);\n`;
|
189 |
|
190 |
|
191 | streams.push(
|
192 | toolbox.vinylStream(filename, source)
|
193 | .pipe(toolbox.plumber())
|
194 |
|
195 | .pipe(include({
|
196 | basePath: paths.directory.root,
|
197 | autoExtension: true,
|
198 | partialPrefix: true,
|
199 | fileProcess: (options) => {
|
200 | return util.babelProcess(options, bundle.scripts.options.babel, babelExtraAllowed);
|
201 | }
|
202 | }))
|
203 |
|
204 | .pipe(gulpif(toMinify, uglify({ output: { comments: 'some' } })))
|
205 |
|
206 | .pipe(gulp.dest(`${paths.directory.root}/${destination}`))
|
207 |
|
208 | .on('finish', () => {
|
209 | toolbox.log(taskName, `'${destination}/${filename}' written`, toolbox.filesize(`${paths.directory.root}/${destination}/${filename}`));
|
210 | })
|
211 | );
|
212 |
|
213 | }
|
214 | }
|
215 |
|
216 | return toolbox.mergeStreams(streams);
|
217 |
|
218 | }, gulp.parallel('scripts-lint', 'scripts-constants', 'scripts-vendors'));
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | flow.createSequence('scripts', gulp.series('scripts-compile'), {
|
227 | cleanBundle: ({ name, bundle }) => {
|
228 | const buildPath = `${paths.directory.root}/${bundle.output.build}/${paths.build.scripts}`;
|
229 | const cachePath = `${paths.directory.cacheScripts}/${name}`;
|
230 |
|
231 | if (env.isScopeSubbundle) {
|
232 | return Object.keys(bundle.scripts.collections).map((collection) => {
|
233 | return [
|
234 | `${buildPath}/${collection}.${paths.extension.scripts}`,
|
235 | `${cachePath}/${collection}.${paths.extension.scripts}`
|
236 | ];
|
237 | }).flat();
|
238 | }
|
239 |
|
240 | return [buildPath, cachePath];
|
241 | }
|
242 | });
|
243 |
|
244 | };
|