Skip to content
This repository was archived by the owner on Feb 21, 2025. It is now read-only.

Commit 0631ff6

Browse files
author
xavier.ternisien
committed
feat(pattern_lab): add patternlab to gulp stack
1 parent 95127e6 commit 0631ff6

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ module.exports = (gulp, userConfig, tasks) => {
2727
require('./lib/css')(gulp, config, tasks);
2828
}
2929

30+
if (config.patternLab.enabled) {
31+
require('./lib/pattern-lab--php-twig')(gulp, config, tasks);
32+
}
33+
3034
if (config.drupal.enabled) {
3135
require('./lib/drupal')(gulp, config, tasks);
3236
}

lib/pattern-lab--php-twig.js

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
'use strict';
2+
const core = require('./core');
3+
const path = require('path');
4+
const yaml = require('js-yaml');
5+
const fs = require('fs');
6+
const inject = require('gulp-inject');
7+
const _ = require('lodash');
8+
const browserSync = require('browser-sync');
9+
const glob = require('glob');
10+
11+
module.exports = (gulp, config, tasks) => {
12+
let plConfig = yaml.safeLoad(
13+
fs.readFileSync(config.patternLab.configFile, 'utf8')
14+
);
15+
const plRoot = path.join(config.patternLab.configFile, '../..');
16+
const plSource = path.join(plRoot, plConfig.sourceDir);
17+
const plPublic = path.join(plRoot, plConfig.publicDir);
18+
const plMeta = path.join(plSource, '/_meta');
19+
const consolePath = path.join(plRoot, 'core/console');
20+
const watchTriggeredTasks = [];
21+
22+
function plBuild(done, errorShouldExit) {
23+
core.sh(`php ${consolePath} --generate`, errorShouldExit, (err) => {
24+
if (config.browserSync.enabled) {
25+
browserSync.get('server').reload();
26+
}
27+
done(err);
28+
});
29+
}
30+
31+
gulp.task('pl', done => plBuild(done, true));
32+
33+
// Begin `<link>` & `<script>` injecting code.
34+
// Will look for these HTML comments in `plSource/_meta/*.twig:
35+
// `<!-- inject:css -->`
36+
// `<!-- endinject -->`
37+
// `<!-- inject:js -->`
38+
// `<!-- endinject -->`
39+
40+
function injectPl(done) {
41+
let sources = [];
42+
if (config.patternLab.injectFiles) {
43+
sources = sources.concat(config.patternLab.injectFiles);
44+
}
45+
console.log(config.js.dest);
46+
sources = sources.concat(glob.sync(path.normalize(`${config.js.dest}/*.js`)));
47+
sources = sources.concat(glob.sync(path.normalize(`${config.css.dest}/*.css`)));
48+
// We need to make sure our JS deps like jQuery are loaded before ours (`config.js.destName`)
49+
const rearrangedSources = [];
50+
sources.forEach((source) => {
51+
if (path.basename(source) === config.js.destName) {
52+
// add to end
53+
rearrangedSources.push(source);
54+
} else {
55+
// add to beginning
56+
rearrangedSources.unshift(source);
57+
}
58+
});
59+
60+
gulp
61+
.src(['*.twig'], { cwd: plMeta })
62+
.pipe(inject(gulp.src(rearrangedSources, { read: false }), {
63+
relative: false,
64+
addRootSlash: false,
65+
addSuffix: '?cacheBuster={{ cacheBuster }}',
66+
addPrefix: path.join('../..', path.relative(plPublic, process.cwd())),
67+
}))
68+
.pipe(gulp.dest(plMeta))
69+
.on('end', done);
70+
}
71+
72+
gulp.task('inject:pl', injectPl);
73+
74+
const plFullDependencies = ['inject:pl'];
75+
76+
// turns scss files full of variables into json files that PL can iterate on
77+
function scssToJson(done) {
78+
config.patternLab.scssToJson.forEach((pair) => {
79+
const scssVarList = _.filter(fs.readFileSync(pair.src, 'utf8').split('\n'), item => _.startsWith(item, pair.lineStartsWith));
80+
// console.log(scssVarList, item.src);
81+
let varsAndValues = _.map(scssVarList, (item) => {
82+
// assuming `item` is `$color-gray: hsl(0, 0%, 50%); // main gray color`
83+
const x = item.split(':');
84+
const y = x[1].split(';');
85+
return {
86+
name: x[0].trim(), // i.e. $color-gray
87+
value: y[0].replace(/!.*/, '').trim(), // i.e. hsl(0, 0%, 50%) after removing `!default`
88+
comment: y[1].replace('//', '').trim(), // any inline comment coming after, i.e. `// main gray color`
89+
};
90+
});
91+
92+
if (!pair.allowVarValues) {
93+
varsAndValues = _.filter(varsAndValues, item => !_.startsWith(item.value, '$'));
94+
}
95+
96+
fs.writeFileSync(pair.dest, JSON.stringify({
97+
items: varsAndValues,
98+
meta: {
99+
description: `To add to these items, use Sass variables that start with <code>${pair.lineStartsWith}</code> in <code>${pair.src}</code>`,
100+
},
101+
}, null, ' '));
102+
});
103+
done();
104+
}
105+
106+
if (config.patternLab.scssToJson) {
107+
gulp.task('pl:scss-to-json', scssToJson);
108+
plFullDependencies.push('pl:scss-to-json');
109+
110+
gulp.task('watch:pl:scss-to-json', () => {
111+
const files = config.patternLab.scssToJson.map(file => file.src);
112+
gulp.watch(files, scssToJson);
113+
});
114+
tasks.watch.push('watch:pl:scss-to-json');
115+
}
116+
117+
function getTwigNamespaceConfig(workingDir) {
118+
workingDir = workingDir || process.cwd(); // eslint-disable-line no-param-reassign
119+
const twigNamespaceConfig = {};
120+
config.patternLab.twigNamespaces.sets.forEach((namespaceSet) => {
121+
const pathArray = namespaceSet.paths.map((pathBase) => {
122+
const results = glob.sync(path.join(pathBase, '**/*.twig')).map((pathItem) => { // eslint-disable-line arrow-body-style
123+
return path.relative(workingDir, path.dirname(pathItem));
124+
});
125+
results.unshift(path.relative(workingDir, pathBase));
126+
return results;
127+
});
128+
twigNamespaceConfig[namespaceSet.namespace] = {
129+
paths: core.uniqueArray(core.flattenArray(pathArray)),
130+
};
131+
});
132+
return twigNamespaceConfig;
133+
}
134+
135+
function addTwigNamespaceConfigToDrupal(done) {
136+
const twigNamespaceConfig = getTwigNamespaceConfig(path.dirname(config.drupal.themeFile));
137+
const drupalThemeFile = yaml.safeLoad(
138+
fs.readFileSync(config.drupal.themeFile, 'utf8')
139+
);
140+
Object.assign(drupalThemeFile['component-libraries'], twigNamespaceConfig);
141+
const newThemeFile = yaml.safeDump(drupalThemeFile);
142+
fs.writeFileSync(config.drupal.themeFile, newThemeFile, 'utf8');
143+
done();
144+
}
145+
146+
function addTwigNamespaceConfigToPl(done) {
147+
const twigNamespaceConfig = getTwigNamespaceConfig(plRoot);
148+
plConfig = yaml.safeLoad(
149+
fs.readFileSync(config.patternLab.configFile, 'utf8')
150+
);
151+
if (!plConfig.plugins) {
152+
Object.assign(plConfig, {
153+
plugins: {
154+
twigNamespaces: { enabled: true, namespaces: {} },
155+
},
156+
});
157+
} else if (!plConfig.plugins.twigNamespaces) {
158+
Object.assign(plConfig.plugins, {
159+
twigNamespaces: { enabled: true, namespaces: {} },
160+
});
161+
} else if (!plConfig.plugins.twigNamespaces.namespaces) {
162+
plConfig.plugins.twigNamespaces.namespaces = {};
163+
}
164+
Object.assign(plConfig.plugins.twigNamespaces.namespaces, twigNamespaceConfig);
165+
const newConfigFile = yaml.safeDump(plConfig);
166+
fs.writeFileSync(config.patternLab.configFile, newConfigFile, 'utf8');
167+
done();
168+
}
169+
170+
if (config.patternLab.twigNamespaces) {
171+
gulp.task('twigNamespaces', (done) => {
172+
addTwigNamespaceConfigToPl(() => {
173+
if (config.patternLab.twigNamespaces.addToDrupalThemeFile) {
174+
addTwigNamespaceConfigToDrupal(done);
175+
}
176+
done();
177+
});
178+
});
179+
plFullDependencies.push('twigNamespaces');
180+
watchTriggeredTasks.push('twigNamespaces');
181+
}
182+
183+
gulp.task('pl:full', gulp.series(plFullDependencies, plBuild));
184+
185+
const watchedExtensions = config.patternLab.watchedExtensions.join(',');
186+
gulp.task('watch:pl', () => {
187+
const plGlob = [path.normalize(`${plSource}/**/*.{${watchedExtensions}}`)];
188+
const src = config.patternLab.extraWatches
189+
? [].concat(plGlob, config.patternLab.extraWatches)
190+
: plGlob;
191+
// plBuild goes last after any deps
192+
watchTriggeredTasks.push(plBuild);
193+
gulp.watch(src, gulp.series(watchTriggeredTasks));
194+
});
195+
196+
tasks.watch.push('watch:pl');
197+
tasks.compile.push('pl:full');
198+
};

0 commit comments

Comments
 (0)