Skip to content

Commit 5b20396

Browse files
authored
Loading uikit resources via the Node resolver (#1246)
* Use NodeJS require module to resolve packages and files/folders in it * Moving the resolver functions to the core package * Rewrote loading the UI kits starting from the config * Adding `package` property to allow a uikit to be used twice with a different name. * Remove obsolete comment * Prevent uikit warnings on our own packages * Fix the resource lookup for starterkits
1 parent 9d5e59c commit 5b20396

File tree

18 files changed

+169
-178
lines changed

18 files changed

+169
-178
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"publish": "npx lerna publish -m \"[skip travis] chore(release): publish %s\"",
4242
"postpublish": "auto release",
4343
"preview:docs": "cd packages/docs && yarn production",
44-
"preview:hbs": "cd packages/development-edition-engine-handlebars && npx patternlab add --starterkits @pattern-lab/starterkit-handlebars-vanilla && npm run pl:build"
44+
"preview:hbs": "cd packages/development-edition-engine-handlebars && yarn pl:starterkit && yarn pl:build"
4545
},
4646
"nyc": {
4747
"exclude": [

packages/cli/bin/install-edition.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const {
1111
writeJsonAsync,
1212
getJSONKey,
1313
} = require('./utils');
14+
const {
15+
resolveFileInPackage,
16+
resolveDirInPackage,
17+
} = require('@pattern-lab/core/src/lib/resolver');
1418

1519
// https://github.com/TehShrike/deepmerge#overwrite-array
1620
const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray;
@@ -31,7 +35,7 @@ const installEdition = (edition, config, projectDir) => {
3135
const sourceDir = config.paths.source.root;
3236
yield checkAndInstallPackage(edition); // 1
3337
yield copyAsync(
34-
path.resolve('./node_modules', edition, 'source', '_meta'),
38+
resolveDirInPackage(edition, 'source', '_meta'),
3539
path.resolve(sourceDir, '_meta')
3640
); // 2
3741
pkg.dependencies = Object.assign(
@@ -45,16 +49,15 @@ const installEdition = (edition, config, projectDir) => {
4549
// 4.1
4650
case '@pattern-lab/edition-node-gulp': {
4751
yield copyAsync(
48-
path.resolve('./node_modules', edition, 'gulpfile.js'),
52+
resolveFileInPackage(edition, 'gulpfile.js'),
4953
path.resolve(sourceDir, '../', 'gulpfile.js')
5054
);
5155
break;
5256
}
5357
// 4.2
5458
case '@pattern-lab/edition-node': {
55-
const editionPath = path.resolve('./node_modules', edition);
56-
const editionConfigPath = path.resolve(
57-
editionPath,
59+
const editionConfigPath = resolveFileInPackage(
60+
edition,
5861
'patternlab-config.json'
5962
);
6063

@@ -67,7 +70,7 @@ const installEdition = (edition, config, projectDir) => {
6770
);
6871

6972
yield copyAsync(
70-
path.join(editionPath, path.sep, 'helpers', path.sep, 'test.js'),
73+
resolveFileInPackage(edition, 'helpers', 'test.js'),
7174
path.resolve(sourceDir, '../', 'helpers/test.js')
7275
);
7376

@@ -76,9 +79,8 @@ const installEdition = (edition, config, projectDir) => {
7679
}
7780
// 4.3
7881
case '@pattern-lab/edition-twig': {
79-
const editionPath = path.resolve('./node_modules', edition);
80-
const editionConfigPath = path.resolve(
81-
editionPath,
82+
const editionConfigPath = resolveFileInPackage(
83+
edition,
8284
'patternlab-config.json'
8385
);
8486
const editionConfig = require(editionConfigPath);
@@ -90,7 +92,7 @@ const installEdition = (edition, config, projectDir) => {
9092
);
9193

9294
yield copyAsync(
93-
path.resolve(editionPath, 'alter-twig.php'),
95+
resolveFileInPackage(edition, 'alter-twig.php'),
9496
path.resolve(sourceDir, '../', 'alter-twig.php')
9597
);
9698

packages/cli/bin/install-plugin.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
'use strict';
22

3-
const path = require('path');
4-
53
const _ = require('lodash');
64

7-
const checkAndInstallPackage = require('./utils').checkAndInstallPackage;
8-
const wrapAsync = require('./utils').wrapAsync;
5+
const { checkAndInstallPackage, wrapAsync } = require('./utils');
6+
const { resolveFileInPackage } = require('@pattern-lab/core/src/lib/resolver');
97

108
const installPlugin = (plugin, config) =>
119
wrapAsync(function*() {
@@ -16,9 +14,7 @@ const installPlugin = (plugin, config) =>
1614
_.set(config, `plugins[${name}]['initialized']`, false);
1715

1816
// Get the options from the plugin, if any
19-
const pluginPathConfig = path.resolve(
20-
path.join(process.cwd(), 'node_modules', name, 'config.json')
21-
);
17+
const pluginPathConfig = resolveFileInPackage(name, 'config.json');
2218
try {
2319
const pluginConfigJSON = require(pluginPathConfig);
2420
if (!_.has(config.plugins[name].options)) {

packages/cli/bin/install-starterkit.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,22 @@ const {
77
checkAndInstallPackage,
88
readJsonAsync,
99
} = require('./utils');
10+
const {
11+
resolvePackageFolder,
12+
resolveDirInPackage,
13+
} = require('@pattern-lab/core/src/lib/resolver');
1014

1115
const installStarterkit = (starterkit, config) =>
1216
wrapAsync(function*() {
1317
const sourceDir = config.paths.source.root;
1418
const name = starterkit.value || starterkit;
1519
yield checkAndInstallPackage(name);
16-
const kitPath = path.resolve('./node_modules', name);
17-
yield copyAsync(path.resolve(kitPath, 'dist'), path.resolve(sourceDir));
20+
yield copyAsync(resolveDirInPackage(name, 'dist'), path.resolve(sourceDir));
1821
let kitConfig;
19-
const kitConfigPath = path.resolve(kitPath, 'patternlab-config.json');
22+
const kitConfigPath = path.join(
23+
resolvePackageFolder(name),
24+
'patternlab-config.json'
25+
);
2026
if (fs.existsSync(kitConfigPath)) {
2127
kitConfig = yield readJsonAsync(kitConfigPath);
2228
}

packages/cli/bin/utils.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const path = require('path');
66
const chalk = require('chalk');
77
const EventEmitter = require('events').EventEmitter;
88
const hasYarn = require('has-yarn');
9+
const { resolveFileInPackage } = require('@pattern-lab/core/src/lib/resolver');
910

1011
/**
1112
* @name log
@@ -124,7 +125,7 @@ const copyWithPattern = (cwd, pattern, dest) =>
124125

125126
/**
126127
* @func fetchPackage
127-
* @desc Fetches and saves packages from npm into node_modules and adds a reference in the package.json under dependencies
128+
* @desc Fetches packages from an npm package registry and adds a reference in the package.json under dependencies
128129
* @param {string} packageName - The package name
129130
*/
130131
const fetchPackage = packageName =>
@@ -193,7 +194,7 @@ const getJSONKey = (packageName, key, fileName = 'package.json') =>
193194
wrapAsync(function*() {
194195
yield checkAndInstallPackage(packageName);
195196
const jsonData = yield fs.readJson(
196-
path.resolve('node_modules', packageName, fileName)
197+
resolveFileInPackage(packageName, fileName)
197198
);
198199
return jsonData[key];
199200
});

packages/core/patternlab-config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"uikits": [
9292
{
9393
"name": "uikit-workshop",
94+
"package": "@pattern-lab/uikit-workshop",
9495
"outputDir": "",
9596
"enabled": true,
9697
"excludedPatternStates": [],

packages/core/src/index.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ const patternlab_module = function(config) {
205205
},
206206

207207
/**
208-
* Installs plugin already available via `node_modules/`
208+
* Installs plugin already available as a package dependency
209209
*
210210
* @memberof patternlab
211211
* @name installplugin
@@ -214,8 +214,6 @@ const patternlab_module = function(config) {
214214
* @returns {void}
215215
*/
216216
installplugin: function(pluginName) {
217-
//get the config
218-
const configPath = path.resolve(process.cwd(), 'patternlab-config.json');
219217
const plugin_manager = new pm();
220218

221219
plugin_manager.install_plugin(pluginName);
@@ -234,7 +232,7 @@ const patternlab_module = function(config) {
234232
},
235233

236234
/**
237-
* Loads starterkit already available via `node_modules/`
235+
* Loads starterkit already available as a package dependency
238236
*
239237
* @memberof patternlab
240238
* @name loadstarterkit

packages/core/src/lib/loaduikits.js

Lines changed: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,91 +5,110 @@ const _ = require('lodash');
55

66
const logger = require('./log');
77

8-
let findModules = require('./findModules'); //eslint-disable-line prefer-const
9-
let fs = require('fs-extra'); // eslint-disable-line
10-
11-
const uiKitMatcher = /^uikit-(.*)$/;
12-
const nodeModulesPath = path.join(process.cwd(), 'node_modules');
13-
14-
/**
15-
* Given a path: return the uikit name if the path points to a valid uikit
16-
* module directory, or false if it doesn't.
17-
* @param filePath
18-
* @returns UIKit name if exists or FALSE
19-
*/
20-
const isUIKitModule = filePath => {
21-
const baseName = path.basename(filePath);
22-
const engineMatch = baseName.match(uiKitMatcher);
8+
const { resolvePackageFolder } = require('./resolver');
239

24-
if (engineMatch) {
25-
return engineMatch[1];
26-
}
27-
return false;
28-
};
10+
let fs = require('fs-extra'); // eslint-disable-line
2911

30-
const readModuleFile = (kit, subPath) => {
12+
const readModuleFile = (uikitLocation, subPath) => {
3113
return fs.readFileSync(
32-
path.resolve(path.join(kit.modulePath, subPath)),
14+
path.resolve(path.join(uikitLocation, subPath)),
3315
'utf8'
3416
);
3517
};
3618

3719
/**
3820
* Loads uikits, connecting configuration and installed modules
39-
* [1] Looks in node_modules for uikits.
40-
* [2] Filter out our uikit-polyfills package.
41-
* [3] Only continue if uikit is enabled in patternlab-config.json
21+
* [1] Lists the enabled uikits from patternlab-config.json
22+
* [2] Try to resolve the location of the uikit in the package dependencies
23+
* [3] Warn when the uikit couldn't be loaded
4224
* [4] Reads files from uikit that apply to every template
4325
* @param {object} patternlab
4426
*/
4527
module.exports = patternlab => {
4628
const paths = patternlab.config.paths;
4729

48-
const uikits = findModules(nodeModulesPath, isUIKitModule) // [1]
49-
.filter(kit => kit.name !== 'polyfills'); // [2]
50-
uikits.forEach(kit => {
51-
const configEntry = _.find(_.filter(patternlab.config.uikits, 'enabled'), {
52-
name: `uikit-${kit.name}`,
53-
}); // [3]
54-
55-
if (!configEntry) {
56-
logger.warning(
57-
`Could not find uikit with name uikit-${kit.name} defined within patternlab-config.json, or it is not enabled.`
58-
);
59-
return;
30+
const uikitConfigs = _.filter(patternlab.config.uikits, 'enabled'); // [1]
31+
uikitConfigs.forEach(uikitConfig => {
32+
let uikitLocation = null;
33+
if ('package' in uikitConfig) {
34+
try {
35+
uikitLocation = resolvePackageFolder(uikitConfig.package);
36+
} catch (ex) {
37+
logger.warning(
38+
`Could not find uikit with package name ${uikitConfig.package}. Did you add it to the 'dependencies' section in your 'package.json' file?`
39+
);
40+
return;
41+
}
42+
} else {
43+
// For backwards compatibility, name to package calculation is:
44+
// 1. name -> name
45+
// 2. name -> uikit-name
46+
// 3. name -> @pattern-lab/name
47+
// 4. name -> @pattern-lab/uikit-name
48+
for (const packageName of [
49+
uikitConfig.name,
50+
`uikit-${uikitConfig.name}`,
51+
`@pattern-lab/${uikitConfig.name}`,
52+
`@pattern-lab/uikit-${uikitConfig.name}`,
53+
]) {
54+
try {
55+
uikitLocation = resolvePackageFolder(packageName); // [2]
56+
} catch (ex) {
57+
// Ignore
58+
}
59+
if (uikitLocation != null) {
60+
uikitConfig.package = packageName;
61+
logger.info(`Found uikit package ${packageName}`);
62+
break;
63+
}
64+
}
65+
if (uikitLocation == null) {
66+
logger.warning(
67+
`Could not find uikit with package name ${uikitConfig.name}, uikit-${uikitConfig.name}, @pattern-lab/${uikitConfig.name} or @pattern-lab/uikit-${uikitConfig.name} defined within patternlab-config.json in the package dependencies.`
68+
);
69+
return;
70+
} else {
71+
logger.warning(
72+
`Please update the configuration of UIKit ${uikitConfig.name} with property 'package: ${uikitConfig.package}' in patternlab-config.json. Lookup by 'name' is deprecated and will be removed in the future.`
73+
);
74+
} // [3]
6075
}
6176

6277
try {
63-
patternlab.uikits[`uikit-${kit.name}`] = {
64-
name: `uikit-${kit.name}`,
65-
modulePath: kit.modulePath,
78+
patternlab.uikits[uikitConfig.name] = {
79+
name: uikitConfig.name,
80+
package: uikitConfig.package,
81+
modulePath: uikitLocation,
6682
enabled: true,
67-
outputDir: configEntry.outputDir,
68-
excludedPatternStates: configEntry.excludedPatternStates,
69-
excludedTags: configEntry.excludedTags,
83+
outputDir: uikitConfig.outputDir,
84+
excludedPatternStates: uikitConfig.excludedPatternStates,
85+
excludedTags: uikitConfig.excludedTags,
7086
header: readModuleFile(
71-
kit,
87+
uikitLocation,
7288
paths.source.patternlabFiles['general-header']
7389
),
7490
footer: readModuleFile(
75-
kit,
91+
uikitLocation,
7692
paths.source.patternlabFiles['general-footer']
7793
),
7894
patternSection: readModuleFile(
79-
kit,
95+
uikitLocation,
8096
paths.source.patternlabFiles.patternSection
8197
),
8298
patternSectionSubType: readModuleFile(
83-
kit,
99+
uikitLocation,
84100
paths.source.patternlabFiles.patternSectionSubtype
85101
),
86-
viewAll: readModuleFile(kit, paths.source.patternlabFiles.viewall),
102+
viewAll: readModuleFile(
103+
uikitLocation,
104+
paths.source.patternlabFiles.viewall
105+
),
87106
}; // [4]
88107
} catch (ex) {
89108
logger.error(ex);
90109
logger.error(
91110
'\nERROR: missing an essential file from ' +
92-
kit.modulePath +
111+
uikitLocation +
93112
paths.source.patternlabFiles +
94113
". Pattern Lab won't work without this file.\n"
95114
);

packages/core/src/lib/resolver.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
5+
/**
6+
* @func resolveFileInPackage
7+
* Resolves a file inside a package
8+
*/
9+
const resolveFileInPackage = (packageName, ...pathElements) => {
10+
return require.resolve(path.join(packageName, ...pathElements));
11+
};
12+
13+
/**
14+
* @func resolvePackageFolder
15+
* Resolves the location of a package on disc
16+
*/
17+
const resolvePackageFolder = packageName => {
18+
return path.dirname(resolveFileInPackage(packageName, 'package.json'));
19+
};
20+
21+
/**
22+
* @func resolveDirInPackage
23+
* Resolves a file inside a package
24+
*/
25+
const resolveDirInPackage = (packageName, ...pathElements) => {
26+
return path.join(resolvePackageFolder(packageName), ...pathElements);
27+
};
28+
29+
module.exports = {
30+
resolveFileInPackage,
31+
resolveDirInPackage,
32+
resolvePackageFolder,
33+
};

packages/core/src/lib/starterkit_manager.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const starterkit_manager = function(config) {
2929
kitDirStats = fs.statSync(kitPath);
3030
} catch (ex) {
3131
logger.warning(
32-
`${starterkitName} not found, use npm to install it first.`
32+
`${starterkitName} not found, use npm or another package manager to install it first.`
3333
);
3434
logger.warning(`${starterkitName} not loaded.`);
3535
return;

0 commit comments

Comments
 (0)