UNPKG

5.41 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8
9var _path = require('path');
10
11var _path2 = _interopRequireDefault(_path);
12
13var _findRoot = require('find-root');
14
15var _findRoot2 = _interopRequireDefault(_findRoot);
16
17var _webpackSources = require('webpack-sources');
18
19var _webpackSources2 = _interopRequireDefault(_webpackSources);
20
21function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
23function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
24
25var ConcatSource = _webpackSources2.default.ConcatSource;
26var isProducation = process.env.NODE_ENV === 'production';
27
28function cleanPath(path) {
29 return path.split('/node_modules/').join('/~/');
30}
31
32// Get closest package definition from path
33function getClosestPackage(modulePath) {
34 var root;
35 var pkg;
36
37 // Catch findRoot or require errors
38 try {
39 root = (0, _findRoot2.default)(modulePath);
40 pkg = require(_path2.default.join(root, 'package.json'));
41 } catch (e) {
42 return null;
43 }
44
45 // If the package.json does not have a name property, try again from
46 // one level higher.
47 // https://github.com/jsdnxx/find-root/issues/2
48 // https://github.com/date-fns/date-fns/issues/264#issuecomment-265128399
49 if (!pkg.name) {
50 return getClosestPackage(_path2.default.resolve(root, '..'));
51 }
52
53 return {
54 package: pkg,
55 path: root
56 };
57}
58
59function check(compilation, modulesToCheck) {
60 var context = compilation.compiler.context;
61 var modules = {};
62
63 function cleanPathRelativeToContext(modulePath) {
64 var cleanedPath = cleanPath(modulePath);
65
66 // Make relative to compilation context
67 if (cleanedPath.indexOf(context) === 0) {
68 cleanedPath = '.' + cleanedPath.replace(context, '');
69 }
70
71 return cleanedPath;
72 }
73
74 compilation.modules.forEach(function (module) {
75 if (!module.resource) {
76 return;
77 }
78
79 var pkg;
80 var packagePath;
81
82 var closestPackage = getClosestPackage(module.resource);
83
84 // Skip module if no closest package is found
85 if (!closestPackage) {
86 return;
87 }
88
89 pkg = closestPackage.package;
90 packagePath = closestPackage.path;
91
92 var modulePath = cleanPathRelativeToContext(packagePath);
93
94 var version = pkg.version;
95
96 if (modulesToCheck.indexOf(pkg.name) < 0) {
97 return;
98 }
99
100 modules[pkg.name] = modules[pkg.name] || [];
101
102 var isSeen = false;
103
104 modules[pkg.name].forEach(function (module) {
105 if (module.version === version) {
106 isSeen = true;
107 }
108 });
109
110 if (!isSeen) {
111 var entry = { version: version, path: modulePath };
112
113 modules[pkg.name].push(entry);
114 }
115 });
116
117 var duplicates = {};
118 Object.keys(modules).forEach(function (name) {
119 if (modules[name].length > 1) {
120 duplicates[name] = modules[name];
121 }
122 });
123
124 return duplicates;
125}
126
127function formatMsg(duplicates) {
128 var error = 'Duplicate (conflicting) packages loaded, make sure to use only one: ';
129
130 if (Object.keys(duplicates).length) {
131 Object.keys(duplicates).forEach(function (key) {
132 var instances = duplicates[key];
133 instances = instances.map(function (version) {
134 var str = version.version + ' ' + version.path;
135 return str;
136 });
137 error += '\\n <' + key + '> \\n';
138 error += ' ' + instances.join('\\n ') + '\\n';
139 });
140 }
141
142 return error;
143}
144
145var DuplicateChecker = function () {
146 function DuplicateChecker(options) {
147 _classCallCheck(this, DuplicateChecker);
148
149 this.options = Object.assign({}, options);;
150 }
151
152 _createClass(DuplicateChecker, [{
153 key: 'apply',
154 value: function apply(compiler) {
155 var modulesToCheck = this.options.modulesToCheck;
156 if (!modulesToCheck || !modulesToCheck.length) {
157 return;
158 }
159
160 compiler.plugin('compilation', function (compilation) {
161 compilation.plugin('optimize-chunk-assets', function (chunks, callback) {
162 chunks.forEach(function (chunk) {
163 // In webpack2 chunk.initial was removed. Use isInitial()
164 try {
165 if (!chunk.initial) return;
166 } catch (e) {
167 if (!chunk.isInitial()) return;
168 }
169
170 var duplicates = check(compilation, modulesToCheck);
171
172 if (Object.keys(duplicates).length && !isProducation) {
173 var errorMessages = formatMsg(duplicates);
174 chunk.files.forEach(function (file) {
175 compilation.assets[file] = new ConcatSource(compilation.assets[file], '\n console.error(\'' + errorMessages + '\');');
176 });
177 }
178 });
179 callback();
180 });
181 });
182 }
183 }]);
184
185 return DuplicateChecker;
186}();
187
188exports.default = DuplicateChecker;
189module.exports = exports['default'];
\No newline at end of file