Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 35 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ This is a Resolver-Plugin for webpack. It enables resolving modules by looking u

Let's look at a simple example.

Suppose you have an application `greeter` to greet users in different languages.
Suppose you have an application `greeter` to greet users in different languages.
The file structure of this application looks something like this:

```
/greeter
- /src
- /de
- /de
- translations.js
- /en
- /en
- translations.js
- ordnial.js
- ordnial.js
- index.js

```

The `translations.js` files contain the translated strings, which are used by index.js.

```js
```js
// /greeter/src/en/translations.js

export default {
Expand All @@ -35,7 +35,7 @@ export default {
};
```

```js
```js
// /greeter/src/de/translations.js

export default {
Expand All @@ -48,40 +48,40 @@ export default {

There are also two `ordnial.js` files containing a function which returns a number with its ordinal postfix.

```js
```js
// /greeter/src/ordnial.js

export default (num) => {
return `${num}.`;
};
```

```js
```js
// /greeter/src/en/ordnial.js
// different ordnial postfixes for en

export default (num) => {
switch (num) {
case 0:
return num;

case 1:
return `${num}st`;

case 2:
return `${num}nd`;

case 3:
return `${num}rd`;

default:
return `${num}th`;
}
};
```


Now suppose you want to create two separate webpack builds for each language.
Now suppose you want to create two separate webpack builds for each language.
The resulting build should only contain the translations strings and the ordinal function for its language.

To do this, you can set up `webpack-fallback-directory-resolver-plugin` to resolve these files based on a language parameter (Environment variable) on build time.
Expand All @@ -108,7 +108,7 @@ module.exports = {
{
prefix: 'language-resolve',
directories: [
// this is the fallback directory chain. The plugin tries to resolve the file first
// this is the fallback directory chain. The plugin tries to resolve the file first
// in the `src/${language}` folder. If it can't be found there, it will try to resolve it in the next directory in the chain, and so on...
path.resolve(__dirname, `src/${language}`),
path.resolve(__dirname, `src`)
Expand All @@ -122,32 +122,32 @@ module.exports = {
```


```js
```js
// /greeter/src/index.js

import translations from "#language-resolve#/translations.js"; // translations is dynamically resolved to
import ordinal from "#language-resolve#/ordnial.js";
import ordinal from "#language-resolve#/ordnial.js";

const greet = (name) => {
console.log(`${translations.hello}`)
};

const greetNthVisitor = (num) => {
// this will output "You are the 1st Visitor" in the en build,
// this will output "You are the 1st Visitor" in the en build,
// and "Du bist der 1. Besucher" in the de build.
console.log(`${translations.nth_visitor_start} ${ordinal(num)} ${translations.visitor}`)
};

export {
export {
greet,
greetNthVisitor
};

```

Another usage example would be a react application, which has multiple themes with different JSX-Markups.
Another usage example would be a react application, which has multiple themes with different JSX-Markups.

For more information, take a look at the [example application](https://github.com/kije/webpack-fallback-directory-resolver-plugin/tree/master/example).
For more information, take a look at the [example application](https://github.com/kije/webpack-fallback-directory-resolver-plugin/tree/master/example).



Expand Down Expand Up @@ -177,14 +177,14 @@ const FallbackDirectoryResolverPlugin = require('webpack-fallback-directory-reso

module.exports = {
// ...

resolve: {
plugins: [
new FallbackDirectoryResolverPlugin(
{
prefix: 'fallback',
directories: [
// this is the fallback directory chain. The plugin tries to resolve the file first
// this is the fallback directory chain. The plugin tries to resolve the file first
// in the `js/dir2` folder. If it can't be found there, it will try to resolve it in the next directory in the chain, and so on...
path.resolve(__dirname, 'js/dir2'),
path.resolve(__dirname, 'js/dir1')
Expand Down Expand Up @@ -217,6 +217,18 @@ An array of directory paths the resolver should try to resolve the imported file

The plugin tries to resolve the file first in the first directory. If it can't find it there, it tries the next directory and so on.

#### extensions
Automatically resolve specified extensions. This is an array of the extensions to resolve automatically, for example
```
extensions: ['.js', '.jsx']
```

#### getRegex
you can provide a function that takes prefix as an argument and returns a regex string used to identify the import paths to resolve.
By default this plugin matches paths in the form #**prefix**#/. If you want your paths to be on the form @**prefix**/ you will provide the following function:
```
getRegex: (prefix) => `^@${prefix}/`
```

## Bugs
If you encounter any bugs, please consider [opening an issue on GitHub](https://github.com/kije/webpack-fallback-directory-resolver-plugin/issues).
If you encounter any bugs, please consider [opening an issue on GitHub](https://github.com/kije/webpack-fallback-directory-resolver-plugin/issues).
16 changes: 14 additions & 2 deletions definitions/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
export interface IFallbackDirectoryResolverPluginOptions {
directories?: string[];
prefix?: string;
extensions?: string[];
getRegex?: (prefix: string) => string;
}
export interface IDirectoryResolverPluginOptions {
directories: string[];
prefix: string;
extensions: string[];
getRegex: (prefix: string) => string;
}
export declare class FallbackDirectoryResolverPlugin {
static defaultOptions: IFallbackDirectoryResolverPluginOptions;
static defaultOptions: IDirectoryResolverPluginOptions;
private options;
private pathRegex;
private cache;
constructor(options?: IFallbackDirectoryResolverPluginOptions);
pathMatchesPrefix(request: string): boolean;
apply(resolver: any): void;
resolveComponentPath(reqPath: string): Promise<string>;
private applyWebpackV4(resolver);
private applyWebpackV3(resolver);
pathsCombinations(reqPath: string, directories: string[], extensions?: string[]): string[];
resolveComponentPath(path: string): string | null;
}
81 changes: 66 additions & 15 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,103 @@ Object.defineProperty(exports, "__esModule", { value: true });
const Promise = require("bluebird");
const fs = require("fs");
const path = require("path");
const existsAsync = (path) => new Promise((resolve) => {
fs.exists(path, resolve);
});
class FallbackDirectoryResolverPlugin {
constructor(options = {}) {
this.options = Object.assign(FallbackDirectoryResolverPlugin.defaultOptions, options);
this.pathRegex = new RegExp(`^#${this.options.prefix}#/`);
this.options = Object.assign({}, FallbackDirectoryResolverPlugin.defaultOptions, options);
this.pathRegex = new RegExp(this.options.getRegex(this.options.prefix));
this.cache = {};
}
pathMatchesPrefix(request) {
return !!request.match(this.pathRegex);
}
apply(resolver) {
if (resolver.ensureHook) {
this.applyWebpackV4(resolver);
}
else {
this.applyWebpackV3(resolver);
}
}
applyWebpackV4(resolver) {
const target = resolver.ensureHook("resolve");
const resolve = (request, resolveContext, callback) => {
if (this.pathMatchesPrefix(request.request)) {
const resolvedComponentPath = this.resolveComponentPath(request.request);
if (resolvedComponentPath) {
const obj = {
directory: request.directory,
path: request.path,
query: request.query,
request: resolvedComponentPath,
};
resolver.doResolve(target, obj, `resolve ${request.request} to ${resolvedComponentPath}`, resolveContext, callback);
}
else {
// todo info
callback();
}
}
else {
callback();
}
};
resolver.getHook("module").tapAsync("ThemeResolverPlugin", resolve);
}
applyWebpackV3(resolver) {
resolver.plugin("module", (request, callback) => {
if (request.request.match(this.pathRegex)) {
const req = request.request.replace(this.pathRegex, "");
this.resolveComponentPath(req).then((resolvedComponentPath) => {
if (this.pathMatchesPrefix(request.request)) {
const resolvedComponentPath = this.resolveComponentPath(request.request);
if (resolvedComponentPath) {
const obj = {
directory: request.directory,
path: request.path,
query: request.query,
request: resolvedComponentPath,
};
resolver.doResolve("resolve", obj, `resolve ${request.request} to ${resolvedComponentPath}`, callback);
}, () => {
}
else {
// todo info
callback();
});
}
}
else {
callback();
}
});
}
resolveComponentPath(reqPath) {
if (!this.cache[reqPath]) {
if (this.options.directories) {
this.cache[reqPath] = Promise.filter(this.options.directories.map((dir) => path.resolve(path.resolve(dir), reqPath)), (item) => existsAsync(item).then((exists) => exists).catch(() => false)).any();
pathsCombinations(reqPath, directories, extensions) {
const paths = directories
.map((dir) => path.resolve(path.resolve(dir), reqPath))
.reduce((prev, path) => {
prev.push(path);
if (extensions) {
extensions.forEach((ext) => prev.push(path + ext));
}
return prev;
}, []);
return paths;
}
resolveComponentPath(path) {
const reqPath = path.replace(this.pathRegex, "");
if (this.cache[reqPath] === undefined) {
const options = this.options;
if (options.directories) {
this.cache[reqPath] =
this.pathsCombinations(reqPath, options.directories, options.extensions).filter((item) => fs.existsSync(item))[0] || null;
}
else {
this.cache[reqPath] = Promise.reject("No Fallback directories!");
this.cache[reqPath] = null;
}
}
return this.cache[reqPath];
}
}
FallbackDirectoryResolverPlugin.defaultOptions = {
extensions: [],
directories: [],
prefix: "fallback",
getRegex: (prefix) => `^#${prefix}#/`,
};
exports.FallbackDirectoryResolverPlugin = FallbackDirectoryResolverPlugin;
module.exports = FallbackDirectoryResolverPlugin;
2 changes: 0 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,3 @@ gulp.task('watch', () => {
gulp.run('build');
});
});

gulp.task('default', ['watch']);
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "webpack-fallback-directory-resolver-plugin",
"version": "0.1.4",
"version": "0.1.4-sl.2",
"description": "Webpack Resolver plugin to resolve modules and files through a fallback chain at compile time.",
"main": "dist/index.js",
"repository": "https://github.com/kije/webpack-fallback-directory-resolver-plugin.git",
Expand Down Expand Up @@ -31,16 +31,16 @@
"webpack": ">= 1.0.0"
},
"dependencies": {
"bluebird": "^3.5.0"
"bluebird": "^3.7.2"
},
"devDependencies": {
"@types/bluebird": "^3.5.11",
"@types/node": "^8.0.30",
"@types/webpack": "^3.0.11",
"gulp": "^3.9.1",
"gulp-cli": "^1.4.0",
"gulp-typescript": "^3.2.2",
"gulp-watch": "^4.3.11",
"gulp": "^4.0.2",
"gulp-cli": "^2.3.0",
"gulp-typescript": "^5.0.1",
"gulp-watch": "^5.0.1",
"merge2": "^1.2.0",
"tslint": "^5.7.0",
"typescript": "^2.5.2"
Expand Down
Loading