Skip to content

Commit 4df68dd

Browse files
committed
- Code refactor and package release
- Handle peer dependencies on binded packages
1 parent 102bb89 commit 4df68dd

9 files changed

+3223
-119
lines changed

.babelrc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"presets": [["@babel/preset-env", {
3+
"targets": {
4+
"node": "8"
5+
}
6+
}]]
7+
}

.eslintrc

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"parser": "babel-eslint",
3+
"extends": "standard",
4+
"rules": {
5+
"comma-dangle": ["error", "always-multiline"],
6+
"semi": ["error", "always"]
7+
}
8+
}

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# exclude lib files and node modules
2+
node_modules
3+
lib

.npmignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# exclude source files and node modules
2+
src
3+
node_modules
4+
5+
# exlude dot files
6+
.babelrc
7+
.eslintrc
8+
.gitignore
9+
.npmignore
10+
11+
# exclude lock file
12+
yarn.lock

package.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "packagebind",
3+
"version": "0.1.0",
4+
"description": "Connect packages to your application with HMR and babel config",
5+
"main": "lib/index.js",
6+
"repository": "https://github.com/interviewstreet/packagebind.git",
7+
"author": "s-yadav <[email protected]>",
8+
"license": "MIT",
9+
"scripts": {
10+
"build": "babel src -d lib"
11+
},
12+
"peerDependencies": {
13+
"babel-plugin-module-resolver": "3.2.0"
14+
},
15+
"dependencies": {
16+
"lodash": "^4.17.11"
17+
},
18+
"devDependencies": {
19+
"@babel/cli": "^7.4.3",
20+
"@babel/core": "^7.4.3",
21+
"@babel/preset-env": "^7.4.3",
22+
"babel-eslint": "^10.0.1",
23+
"eslint": "^5.16.0",
24+
"eslint-config-standard": "^12.0.0",
25+
"eslint-plugin-import": "^2.17.0",
26+
"eslint-plugin-node": "^8.0.1",
27+
"eslint-plugin-promise": "^4.1.1",
28+
"eslint-plugin-standard": "^4.0.0"
29+
}
30+
}

src/index.js

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import path from 'path';
2+
import { resolvePath } from 'babel-plugin-module-resolver';
3+
import { cloneDeep } from 'lodash';
4+
5+
import {
6+
isFromCurrentRepo,
7+
findRepoRootPath,
8+
getLinkedBabelrc,
9+
getLinkedPackageJSON,
10+
getAliases,
11+
getFilesRepo,
12+
} from './utils';
13+
14+
/**
15+
* Get the new babel config with optimized settings for linked aliases
16+
*/
17+
export default function packagebind (babelConfig) {
18+
/** We are cloning babelrc here so we can mutate it directly to keep logic simpler */
19+
const cloneBabelrc = cloneDeep(babelConfig);
20+
const { plugins = [] } = cloneBabelrc;
21+
22+
const moduleResolver = plugins.find(
23+
plugin => Array.isArray(plugin) && plugin[0] === 'module-resolver'
24+
);
25+
26+
const aliases = getAliases(plugins);
27+
28+
const linkedRepos = Object.keys(aliases).filter((aliasKey) => {
29+
const aliasPath = path.resolve(aliases[aliasKey]);
30+
return isFromCurrentRepo(aliasPath);
31+
});
32+
33+
const linkedReposMeta = linkedRepos.map((name) => {
34+
const rootPath = findRepoRootPath(aliases[name]);
35+
const babelConfig = getLinkedBabelrc(rootPath);
36+
const packageJSON = getLinkedPackageJSON(rootPath);
37+
return {
38+
name,
39+
rootPath,
40+
babelConfig,
41+
packageJSON,
42+
};
43+
});
44+
45+
/** TODO: Add plugins from the linked packages as well.
46+
* For now that is not required as the plugins added on this repo is super set of all plugin used on linked repos
47+
* For now just get the alias from those babel files
48+
* */
49+
50+
const aliasMaps = {};
51+
52+
linkedReposMeta.forEach((meta) => {
53+
const { babelConfig, name, rootPath, packageJSON } = meta;
54+
55+
aliasMaps[name] = {};
56+
57+
// Add alias from linked babelConfig
58+
if (babelConfig) {
59+
const aliases = getAliases(babelConfig.plugins);
60+
if (aliases) {
61+
aliasMaps[name] = Object.entries(aliases).reduce((updatedAliases, [key, value]) => {
62+
updatedAliases[key] = path.resolve(rootPath, value);
63+
return updatedAliases;
64+
}, aliasMaps[name]);
65+
}
66+
}
67+
68+
// Add peer dependencies to aliasMaps to make sure the dependency conflict doesn't happens
69+
if (packageJSON.peerDependencies) {
70+
Object.keys(packageJSON.peerDependencies).forEach((module) => {
71+
aliasMaps[name][module] = path.resolve(rootPath, 'node_modules', module);
72+
});
73+
}
74+
});
75+
76+
moduleResolver[1].resolvePath = (sourcePath, currentFile, opts) => {
77+
opts = cloneDeep(opts);
78+
const repo = getFilesRepo(currentFile, linkedReposMeta);
79+
if (repo !== 'currentRepo' && aliasMaps[repo]) {
80+
opts.alias = { ...opts.alias, ...aliasMaps[repo] };
81+
}
82+
const realPath = resolvePath(sourcePath, currentFile, opts);
83+
return realPath;
84+
};
85+
86+
return cloneBabelrc;
87+
}

src/packagebind.js

-119
This file was deleted.

src/utils.js

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { readFileSync, existsSync } from 'fs';
2+
import path from 'path';
3+
4+
/**
5+
* For a given path return if the path is from current repo or not
6+
*/
7+
export function isFromCurrentRepo(filePath) {
8+
const currentRepoDir = process.cwd();
9+
return filePath.startsWith(currentRepoDir);
10+
}
11+
12+
/**
13+
* given a alias path find the root path for that repo
14+
* */
15+
export function findRepoRootPath(aliasPath) {
16+
const fullAliasPath = path.resolve(aliasPath);
17+
let rootPath = fullAliasPath;
18+
19+
while (rootPath.includes('/') && !existsSync(`${rootPath}/package.json`)) {
20+
rootPath = rootPath.substring(0, rootPath.lastIndexOf('/'));
21+
}
22+
23+
return rootPath;
24+
}
25+
26+
/**
27+
* given a repo path get the babel config of the linked repository
28+
* */
29+
export function getLinkedBabelrc(repoPath) {
30+
if (existsSync(`${repoPath}/.babelrc`)) {
31+
return JSON.parse(readFileSync(`${repoPath}/.babelrc`, 'utf8'));
32+
} else if (existsSync(`${repoPath}/babel.config.js`)) {
33+
return require(`${repoPath}/babel.config.js`);
34+
}
35+
return null;
36+
}
37+
38+
/**
39+
* given a repo path return its package.json
40+
*/
41+
export function getLinkedPackageJSON(repoPath) {
42+
if (existsSync(`${repoPath}/package.json`)) {
43+
return JSON.parse(readFileSync(`${repoPath}/package.json`, 'utf8'));
44+
} else if (existsSync(`${repoPath}/babel.config.js`)) {
45+
return {};
46+
}
47+
}
48+
49+
/**
50+
* From the plugins array of a babel config extract the aliases.
51+
* */
52+
export function getAliases(plugins = []) {
53+
const moduleResolver = plugins.find(
54+
plugin => Array.isArray(plugin) && plugin[0] === 'module-resolver'
55+
);
56+
if (moduleResolver) {
57+
return moduleResolver[1].alias;
58+
}
59+
return null;
60+
}
61+
62+
63+
/**
64+
* Finds the repository name on which the file path exist.
65+
* It returns currentRepo if the file is from the same repo, otherwise it returns the repository name
66+
*/
67+
export function getFilesRepo(filePath, linkedReposMeta) {
68+
if (isFromCurrentRepo(filePath)) {
69+
return 'currentRepo';
70+
}
71+
72+
return linkedReposMeta.find(({ rootPath }) => filePath.startsWith(rootPath)).name;
73+
}

0 commit comments

Comments
 (0)