-
-
Notifications
You must be signed in to change notification settings - Fork 87
/
index.js
195 lines (166 loc) · 7.33 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
'use strict';
var util = require('util')
, resolve = require('resolve')
, exposify = require('exposify')
, format = require('util').format
, path = require('path')
, through = require('through')
, resolveShims = require('./lib/resolve-shims')
, rename = require('rename-function-calls')
, debug = require('./lib/debug')
var shimRequire = '__browserify_shim_require__';
function requireDependencies(depends, packageRoot, browserAliases, dependencies) {
if (!depends) return '';
function customResolve (k) {
// resolve aliases to full paths to avoid conflicts when require is injected into a file
// inside another package, i.e. the it's shim was defined in a package.json one level higher
// aliases don't get resolved by browserify in that case, since it only looks in the package.json next to it
var browserAlias = browserAliases && browserAliases[k]
, dependency = dependencies && dependencies[k]
, alias;
try {
// prefer browser aliases defined explicitly
alias = browserAlias
? path.resolve(packageRoot, browserAlias)
// but also consider dependencies installed in the package in which shims were defined
: dependency
? resolve.sync(k, { basedir: packageRoot })
// lets hope for the best that browserify will be able to resolve this, cause we can't
: k;
} catch (err) {
// resolve.sync may fail, in which case we give up and hope browserify can figure it out
alias = k;
}
return { alias: alias, exports: depends[k] || null };
}
function noResolve(k) {
return { alias: k, exports: depends[k] || null };
}
return Object.keys(depends)
// if the package was looked up from the parent of its enclosing package we need to pre-resolve the depends
.map(customResolve)
.reduce(
function (acc, dep) {
var alias = dep.alias.replace(/\\/g, "\\\\");
return dep.exports
// Example: jQuery = global.jQuery = require("jquery");
// the global dangling variable is needed cause some libs reference it as such and it breaks outside of the browser,
// i.e.: (function ($) { ... })( jQuery )
// This little extra makes it work everywhere and since it's on top, it will be shadowed by any other definitions
// so it doesn't conflict with anything.
? acc + dep.exports + ' = global.' + dep.exports + ' = require("' + alias + '");\n'
: acc + 'require("' + alias + '");\n';
}
, '\n; '
);
}
function bindWindowWithExports(s, dependencies) {
// purposely make module, exports, require and define be 'undefined',
// but pass a function that allows exporting our dependency from the window or the context
// This results in code similarly to this example which shims ember which depends on jquery:
/**
* -- browserify wrapper
* function(require,module,exports){
*
* -- our deps (which still have access to require)
* jquery = global.jquery = require("/full/path/to/jquery.js");
*
* -- assigning shimmed require to actual require
* -- this shouldn't matter, but would fix cases where libraries reach __browserify_shim_require__(x) as long
* -- as x was included in the bundle
*
* __browserify_shim_require__=require;
*
* -- also it won't hurt anything
*
* -- browserify-shim wrapper
* (function browserifyShim(module, exports, require, define, browserify_shim__define__module__export__) {
* -- inside this function neither module, exports, require, or define are defined
*
* -- browserify_shim__define__module__export__ allows exporting (since module and exports aren't available)
*
* [..] -- code that needs shimming
*
* -- exporting whatever ember attached to the window
* ; browserify_shim__define__module__export__(typeof ember != "undefined" ? ember : window.ember);
*
* }).call(global, undefined, undefined, undefined, undefined, function defineExport(ex) { module.exports = ex; });
* -- browserify-shim wrapper closed
* }
* -- browserify wrapper closed
*/
// Shadowing require is necessary to fix code that tries to do common-js, but ends up requiring deps that cannot be resolved
// In the case below we want the below condition to be false at run time.
/**
* if (!jQuery && typeof require === 'function') {
* jQuery = require('jquery');
* }
*/
// Additionally `require('jquery')` needs to be refactored to prevent browserify from looking for 'jquery' at bundle time.
// The rewriting step happens inside the main @see shim function.
// Thus it gets rewritten via rename-function-calls:
/**
* if (!jQuery && typeof require === 'function') {
* jQuery = __browserify_shim_removed_require__('jquery');
* }
*/
// The fact that __browserify_shim_removed_require__ is not defined doesn't matter since we never enter that block.
return dependencies
+ '; var ' + shimRequire + '=require;'
+ '(function browserifyShim(module, exports, require, define, browserify_shim__define__module__export__) {\n'
+ s
+ '\n}).call(global, undefined, undefined, undefined, undefined, function defineExport(ex) { module.exports = ex; });\n';
}
function bindWindowWithoutExports(s, dependencies) {
// if a module doesn't need anything to be exported, it is likely, that it exports itself properly
// therefore it is not a good idea to override the module here, however we need to still disable require
// all else is similar to @see bindWindowWithExports
return dependencies
+ '; var ' + shimRequire + '=require;'
+ '(function browserifyShim(module, define, require) {\n'
+ s
+ '\n}).call(global, module, undefined, undefined);\n';
}
function moduleExport(exp) {
return format('\n; browserify_shim__define__module__export__(typeof %s != "undefined" ? %s : window.%s);\n', exp, exp, exp);
}
function wrap(content, config, packageRoot, browserAliases) {
var exported = config.exports
? content + moduleExport(config.exports)
: content
, dependencies = requireDependencies(config.depends, packageRoot, browserAliases)
, boundWindow = config.exports
? bindWindowWithExports(exported, dependencies)
: bindWindowWithoutExports(exported, dependencies);
return boundWindow;
}
module.exports = function shim(file) {
var content = '';
var stream = through(write, end);
return stream;
function write(buf) { content += buf; }
function end() {
var messages = [];
resolveShims(file, messages, function (err, info) {
if (err) {
stream.emit('error', err);
return stream.queue(null);
}
debug('');
debug.inspect({ file: file, info: info, messages: messages });
var eg = info.exposeGlobals;
if(eg && Object.keys(eg)) {
content = exposify.expose(eg, content);
}
if (info.shim) {
// at this point we consider all remaining (not exposified) require statements to be invalid (why else are we shimming this)
content = rename('require', shimRequire, content);
var transformed = wrap(content, info.shim, info.packageDir, info.browser)
stream.queue(transformed);
} else {
stream.queue(content);
}
stream.queue(null);
});
}
}