1 |
|
2 |
|
3 |
|
4 | 'use strict';
|
5 |
|
6 |
|
7 | const Fiber = require('fibers');
|
8 | const gulp = require('gulp');
|
9 | const autoprefixer = require('gulp-autoprefixer');
|
10 | const cache = require('gulp-cached');
|
11 | const cssnano = require('gulp-cssnano');
|
12 | const gulpif = require('gulp-if');
|
13 | const imagemin = require('gulp-imagemin');
|
14 | const insert = require('gulp-insert');
|
15 | const jsonsass = require('gulp-json-sass');
|
16 | const rename = require('gulp-rename');
|
17 | const gulpsass = require('gulp-sass');
|
18 | const sourcemaps = require('gulp-sourcemaps');
|
19 | const stylelint = require('gulp-stylelint');
|
20 | const cloneDeep = require('lodash.clonedeep');
|
21 | const pluralize = require('pluralize');
|
22 | const sass = require('sass');
|
23 | const jsonToScss = require('@absolunet/json-to-scss');
|
24 | const env = require('~/helpers/env');
|
25 | const flow = require('~/helpers/flow');
|
26 | const paths = require('~/helpers/paths');
|
27 | const toolbox = require('~/helpers/toolbox');
|
28 | const util = require('~/helpers/util');
|
29 |
|
30 |
|
31 | module.exports = () => {
|
32 |
|
33 |
|
34 | flow.createTask('styles-images', () => {
|
35 | return gulp.src(paths.files.inline, { base: paths.directory.root })
|
36 | .pipe(toolbox.plumber())
|
37 | .pipe(imagemin())
|
38 | .pipe(rename(util.assetsRename()))
|
39 | .pipe(gulp.dest(paths.directory.cache))
|
40 | ;
|
41 | });
|
42 |
|
43 |
|
44 |
|
45 | flow.createTask('styles-lint', ({ taskName }) => {
|
46 |
|
47 | let hasErrors = false;
|
48 |
|
49 | return gulp.src(paths.files.stylesLint)
|
50 |
|
51 |
|
52 | .pipe(cache('styles', { optimizeMemory: true }))
|
53 |
|
54 | .pipe(stylelint({
|
55 | configFile: paths.config.stylelint,
|
56 | syntax: 'scss',
|
57 | failAfterError: true,
|
58 | reporters: [
|
59 | {
|
60 | formatter: (results) => {
|
61 | hasErrors = false;
|
62 |
|
63 | results.forEach((item) => {
|
64 | if (item.warnings.length !== 0 || item.deprecations.length !== 0 || item.invalidOptionWarnings.length !== 0) {
|
65 | delete cache.caches.styles[item.source];
|
66 |
|
67 | if (!hasErrors) {
|
68 | item.warnings.forEach((flag) => {
|
69 | if (flag.severity === 'error') {
|
70 | hasErrors = true;
|
71 | }
|
72 | });
|
73 | }
|
74 | }
|
75 | });
|
76 |
|
77 | if (!hasErrors) {
|
78 | toolbox.log(taskName, `${pluralize('file', results.length, true)} linted`);
|
79 | }
|
80 | }
|
81 | },
|
82 | {
|
83 | formatter: 'string',
|
84 | console: true
|
85 | },
|
86 | {
|
87 | formatter: () => {
|
88 | flow.showDelayedLog(hasErrors);
|
89 | }
|
90 | }
|
91 | ]
|
92 | }))
|
93 | ;
|
94 | });
|
95 |
|
96 |
|
97 |
|
98 | flow.createTask('styles-constants', ({ taskName }) => {
|
99 | const streams = [];
|
100 |
|
101 | for (const name of Object.keys(env.bundles)) {
|
102 | const data = util.parseKonstan('styles', name, env.bundles[name].output);
|
103 | data.bundle = `'${name}'`;
|
104 |
|
105 | const konstanJson = JSON.stringify({ konstan: data });
|
106 |
|
107 |
|
108 | streams.push(
|
109 | toolbox.vinylStream(paths.filename.konstanStyles, konstanJson)
|
110 | .pipe(toolbox.plumber())
|
111 | .pipe(jsonsass())
|
112 | .pipe(insert.prepend(`${jsonToScss.convert(konstanJson)}\n\n`))
|
113 | .pipe(gulp.dest(`${paths.directory.cacheStyles}/${name}`))
|
114 | );
|
115 |
|
116 | }
|
117 |
|
118 | return toolbox.mergeStreams(streams).on('finish', () => {
|
119 | flow.skipOnWatch(taskName);
|
120 | toolbox.log(taskName, `${pluralize('file', streams.length, true)} generated`);
|
121 | });
|
122 | });
|
123 |
|
124 |
|
125 |
|
126 | gulpsass.compiler = sass;
|
127 |
|
128 | flow.createTask('styles-compile', ({ taskName }) => {
|
129 | const sassFunctions = require(paths.config.sassFunctions);
|
130 |
|
131 | const streams = [];
|
132 |
|
133 | for (const name of Object.keys(env.bundles)) {
|
134 | const bundle = env.bundles[name];
|
135 |
|
136 |
|
137 | for (const collection of Object.keys(bundle.styles.collections)) {
|
138 | const list = cloneDeep(bundle.styles.collections[collection]);
|
139 |
|
140 |
|
141 | list.unshift(`${paths.directory.cacheStyles}/${name}/${paths.filename.konstan}`);
|
142 |
|
143 |
|
144 | list.forEach((file, i) => {
|
145 | list[i] = `@import '${file}';`;
|
146 | });
|
147 |
|
148 | const toMinify = (bundle.styles.options.minify && !env.watching) || env.production;
|
149 | const toSourcemaps = bundle.styles.options.sourcemaps && !env.production;
|
150 | const filename = `${collection}.${paths.extension.build}`;
|
151 | const filenameBuild = `${collection}.${paths.extension.stylesBuild}`;
|
152 | const destination = `${bundle.output.build}/${paths.build.styles}`;
|
153 | const source = `${util.getGeneratedBanner(name)}${list.join('\n')}\n`;
|
154 |
|
155 |
|
156 | streams.push(
|
157 | toolbox.vinylStream(filename, source)
|
158 | .pipe(toolbox.plumber())
|
159 |
|
160 | .pipe(gulpif(toSourcemaps, sourcemaps.init()))
|
161 |
|
162 | .pipe(
|
163 | gulpsass({
|
164 | fiber: Fiber,
|
165 | includePaths: [paths.directory.root],
|
166 | functions: sassFunctions
|
167 |
|
168 | })
|
169 | .on('error', gulpsass.logError)
|
170 | )
|
171 |
|
172 | .pipe(autoprefixer({ overrideBrowserslist: bundle.styles.options.autoprefixer }))
|
173 |
|
174 | .pipe(gulpif(toMinify, cssnano({ autoprefixer: false, discardUnused: false, mergeIdents: false, reduceIdents: false, zindex: false })))
|
175 |
|
176 | .pipe(gulpif(toSourcemaps, sourcemaps.write('maps', {
|
177 | includeContent: false,
|
178 | sourceRoot: 'source'
|
179 | })))
|
180 |
|
181 | .pipe(gulp.dest(`${paths.directory.root}/${destination}`))
|
182 |
|
183 | .on('finish', () => {
|
184 | toolbox.log(taskName, `'${destination}/${filenameBuild}' written`, toolbox.filesize(`${paths.directory.root}/${destination}/${filenameBuild}`));
|
185 | })
|
186 | );
|
187 |
|
188 | }
|
189 | }
|
190 |
|
191 | return toolbox.mergeStreams(streams);
|
192 |
|
193 | }, gulp.parallel('styles-lint', 'styles-constants'));
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | flow.createSequence('styles', gulp.series('styles-images', 'styles-compile'), {
|
202 | cleanPaths: [paths.directory.cacheInline],
|
203 | cleanBundle: ({ name, bundle }) => {
|
204 | const buildPath = `${paths.directory.root}/${bundle.output.build}/${paths.build.styles}`;
|
205 | const cachePath = `${paths.directory.cacheStyles}/${name}`;
|
206 |
|
207 | if (env.isScopeSubbundle) {
|
208 | return Object.keys(bundle.styles.collections).map((collection) => {
|
209 | return [
|
210 | `${buildPath}/${collection}.${paths.extension.stylesBuild}`,
|
211 | `${cachePath}/${collection}.${paths.extension.stylesBuild}`
|
212 | ];
|
213 | }).flat();
|
214 | }
|
215 |
|
216 | return [buildPath, cachePath];
|
217 | }
|
218 | });
|
219 |
|
220 | };
|