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

Commit 54aaaa3

Browse files
author
blaryjp
authored
Merge pull request #10 from JavierTern/feat/patternLab
feat(pattern_lab): add patternlab to gulp stack
2 parents 95127e6 + 322080b commit 54aaaa3

File tree

2 files changed

+200
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)