├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── README.md
├── e2e
├── index.js
└── modules
│ ├── bar.html
│ ├── bar.js
│ ├── foo.html
│ ├── foo.js
│ ├── index-absolute.js
│ ├── index-module.js
│ └── index-relative.js
├── index.js
├── package.json
└── test
└── index.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 4
9 | max_line_length = 120
10 | trim_trailing_whitespace = true
11 |
12 | [{*.json,.*rc}]
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "spartez"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | # Created by https://www.gitignore.io/api/node
3 |
4 | ### Node ###
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # node-waf configuration
29 | .lock-wscript
30 |
31 | # Compiled binary addons (http://nodejs.org/api/addons.html)
32 | build/Release
33 |
34 | # Dependency directories
35 | node_modules
36 | jspm_packages
37 |
38 | # Optional npm cache directory
39 | .npm
40 |
41 | # Optional eslint cache
42 | .eslintcache
43 |
44 | # Optional REPL history
45 | .node_repl_history
46 |
47 | # Output of 'npm pack'
48 | *.tgz
49 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '6'
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Module Mapping Webpack Plugin [](http://travis-ci.org/spartez/module-mapping-webpack-plugin)
2 |
3 | This is a [webpack](https://webpack.github.io) plugin for mapping modules onto different files.
4 |
5 | ## Installation
6 |
7 | Install the plugin with npm:
8 |
9 | ```sh
10 | $ npm install module-mapping-webpack-plugin --save-dev
11 | ```
12 |
13 | ## Usage
14 |
15 | ```js
16 | // webpack.config.js
17 | const webpack = require('webpack');
18 | const ModuleMappingPlugin = require('module-mapping-webpack-plugin');
19 |
20 | module.exports = {
21 | // ...
22 | plugins: [
23 | new ModuleMappingPlugin({
24 | './foo.js': './foo-spartez.js',
25 | // ...
26 | })
27 | ]
28 | };
29 |
30 | // foo.js
31 | export default () => console.log('Hello World!');
32 |
33 | // foo-spartez.js
34 | export default () => console.log('Hello Spartez!');
35 |
36 | // index.js
37 | import foo from './foo';
38 | foo(); // → 'Hello Spartez!';
39 | ```
40 | ## License
41 |
42 | The MIT License
43 |
44 | Copyright :copyright: 2017 Spartez, https://spartez.com
45 |
--------------------------------------------------------------------------------
/e2e/index.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import path from 'path';
3 | import fs from 'fs-extra';
4 | import webpack from 'webpack';
5 | import ModuleMappingPlugin from '../';
6 |
7 | const outputPath = path.resolve('../dist');
8 |
9 | async function build(config) {
10 | return new Promise((resolve, reject) => webpack(config, (err, stats) => {
11 | if (err || stats.hasErrors()) {
12 | reject(err || stats.toJson('errors-only')
13 | .errors);
14 | return;
15 | }
16 | resolve(`${config.output.path}/${config.output.filename}`);
17 | }));
18 | }
19 |
20 | function createConfig(entry, pluginConfig) {
21 | return {
22 | entry,
23 | output: {
24 | path: outputPath,
25 | filename: `bundle_${Date.now()}.js`,
26 | library: 'test',
27 | libraryTarget: 'commonjs2'
28 | },
29 | resolve: {
30 | root: [path.resolve('./modules')]
31 | },
32 | module: {
33 | loaders: [
34 | { test: /\.html$/, loader: 'raw' }
35 | ]
36 | },
37 | plugins: [
38 | ModuleMappingPlugin(pluginConfig)
39 | ]
40 | };
41 | }
42 |
43 | function testPathType(pathType) {
44 |
45 | test(`should not map anything when using ${pathType} paths`, async t => {
46 | const bundlePath = await build(createConfig(`./modules/index-${pathType}.js`, {}));
47 | const testModule = require(bundlePath);
48 | t.is(testModule.fn(), 'foo');
49 | });
50 |
51 |
52 | test(`should map foo.js to bar.js when using ${pathType} paths`, async t => {
53 | const bundlePath = await build(createConfig(`./modules/index-${pathType}.js`, {
54 | './modules/foo.js': './modules/bar.js'
55 | }));
56 | const testModule = require(bundlePath);
57 | t.is(testModule.fn(), 'bar');
58 | t.is(testModule.html.trim(), '
foo
');
59 | });
60 |
61 |
62 | test(`should map foo.html to bar.html when using ${pathType} paths`, async t => {
63 | const bundlePath = await build(createConfig(`./modules/index-${pathType}.js`, {
64 | './modules/foo.html': './modules/bar.html'
65 | }));
66 | const testModule = require(bundlePath);
67 | t.is(testModule.fn(), 'foo');
68 | t.is(testModule.html.trim(), 'bar
');
69 | });
70 |
71 |
72 | test(`should map both foo.js and foo.html when using ${pathType} paths`, async t => {
73 | const bundlePath = await build(createConfig(`./modules/index-${pathType}.js`, {
74 | './modules/foo.js': './modules/bar.js',
75 | './modules/foo.html': './modules/bar.html'
76 | }));
77 | const testModule = require(bundlePath);
78 | t.is(testModule.fn(), 'bar');
79 | t.is(testModule.html.trim(), 'bar
');
80 | });
81 |
82 | }
83 |
84 | testPathType('relative');
85 | testPathType('absolute');
86 | testPathType('module');
87 |
88 | test.after.always('cleanup dist folder', t => fs.remove(outputPath));
89 |
--------------------------------------------------------------------------------
/e2e/modules/bar.html:
--------------------------------------------------------------------------------
1 | bar
2 |
--------------------------------------------------------------------------------
/e2e/modules/bar.js:
--------------------------------------------------------------------------------
1 | module.exports = () => 'bar';
2 |
--------------------------------------------------------------------------------
/e2e/modules/foo.html:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/e2e/modules/foo.js:
--------------------------------------------------------------------------------
1 | module.exports = () => 'foo';
2 |
--------------------------------------------------------------------------------
/e2e/modules/index-absolute.js:
--------------------------------------------------------------------------------
1 | module.exports.fn = require(__dirname + '/foo');
2 | module.exports.html = require(__dirname + '/foo.html');
3 |
--------------------------------------------------------------------------------
/e2e/modules/index-module.js:
--------------------------------------------------------------------------------
1 | module.exports.fn = require('foo');
2 | module.exports.html = require('foo.html');
3 |
--------------------------------------------------------------------------------
/e2e/modules/index-relative.js:
--------------------------------------------------------------------------------
1 | module.exports.fn = require('./foo');
2 | module.exports.html = require('./foo.html');
3 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | function ModuleMappingPlugin(mappings) {
4 | const absoluteMappings = Object.keys(mappings)
5 | .reduce((current, key) => Object.assign({}, current, {
6 | [path.resolve(key)]: path.resolve(mappings[key])
7 | }), {});
8 |
9 | const mappingExists = data => !!absoluteMappings[data.resource];
10 |
11 | const overrideResource = data => Object.assign({}, data, {
12 | userRequest: absoluteMappings[data.resource],
13 | resource: absoluteMappings[data.resource]
14 | });
15 |
16 | return {
17 | apply: compiler => {
18 | compiler.plugin('normal-module-factory', moduleFactory => {
19 | moduleFactory.plugin('after-resolve', (data, callback) => {
20 | mappingExists(data) ? callback(null, overrideResource(data)) : callback(null, data);
21 | });
22 | });
23 | }
24 | };
25 | }
26 |
27 | module.exports = ModuleMappingPlugin;
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "module-mapping-webpack-plugin",
3 | "version": "1.1.1",
4 | "description": "Webpack plugin for mapping modules to different files",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "ava && eslint ."
8 | },
9 | "keywords": [
10 | "webpack",
11 | "plugin",
12 | "mapping",
13 | "modules"
14 | ],
15 | "author": "Spartez",
16 | "license": "MIT",
17 | "devDependencies": {
18 | "ava": "^0.16.0",
19 | "eslint-config-spartez": "^1.0.0",
20 | "fs-extra": "^0.30.0",
21 | "raw-loader": "^0.5.1",
22 | "webpack": "^1.13.2"
23 | },
24 | "ava": {
25 | "files": [
26 | "test/index.js",
27 | "e2e/index.js"
28 | ],
29 | "verbose": true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import path from 'path';
3 | import ModuleMappingPlugin from '../';
4 |
5 | function mock(pluginFn) {
6 | return {
7 | plugin: pluginFn
8 | };
9 | }
10 |
11 | function handleRequest(fn, request) {
12 | return new Promise((resolve, reject) => fn({
13 | userRequest: request,
14 | resource: request
15 | }, (err, data) => {
16 | if (err) {
17 | reject(err);
18 | } else {
19 | resolve(data);
20 | }
21 | }));
22 | }
23 |
24 | test.cb('should map foo.js to bar.js', t => {
25 | const plugin = ModuleMappingPlugin({
26 | './foo.js': './bar.js'
27 | });
28 |
29 | const input = [{
30 | request: path.resolve('./foo.js'),
31 | expected: path.resolve('./bar.js')
32 | }];
33 |
34 | const moduleFactory = mock((name, fn) => {
35 | t.is(name, 'after-resolve');
36 | Promise.all(
37 | input.map(({ request, expected }) =>
38 | handleRequest(fn, request)
39 | .then(data => {
40 | t.is(data.userRequest, expected);
41 | t.is(data.resource, expected);
42 | })
43 | ))
44 | .then(() => t.end())
45 | .catch(t.end);
46 | });
47 |
48 | const compiler = mock((name, fn) => {
49 | t.is(name, 'normal-module-factory');
50 | fn(moduleFactory);
51 | });
52 |
53 | plugin.apply(compiler);
54 | });
55 |
--------------------------------------------------------------------------------