forked from ember-cli/ember-fetch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
176 lines (154 loc) · 6.1 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
/* eslint-env node */
'use strict';
var path = require('path');
var map = require('broccoli-stew').map;
/*
* The `index.js` file is the main entry point for all Ember CLI addons. The
* object we export from this file is turned into an Addon class
* (https://github.com/ember-cli/ember-cli/blob/master/lib/models/addon.js) by
* Ember CLI.
*
* This addon is relatively simple: it includes both `node-fetch` and
* `whatwg-fetch` as npm dependencies, and swaps the correct version in
* depending on whether the Ember app is being built for FastBoot or the
* browser.
*
* At a high-level, the flow for this addon is:
*
* 1. When a build starts and the addon is included, tell Ember CLI to import
* `vendor/fetch.js` into the vendor.js file. `vendor/fetch.js` doesn't
* actually exist yet; we'll create it later.
* 2. When Ember CLI asks for the addon's vendor tree, we'll return a Broccoli
* tree that contains the correct fetch() version.
* 3. In the case of the browser polyfill, we wrap it in a shim that that makes
* it compatible with Ember's module system. (Normally the polyfill exports a
* global, but we can rely on the fact that Ember users are using modules.)
*/
module.exports = {
name: 'ember-fetch',
/*
* The `included` hook is invoked at the very beginning of the build process.
* It gets passed the `EmberApp` model
* (https://github.com/ember-cli/ember-cli/blob/master/lib/broccoli/ember-app.js),
* which allows us to use the `import()` method to tell it to include a file
* from our `vendor` tree into the final built app.
*/
included: function(app) {
this._super.included.apply(this, arguments);
let target = app;
if (typeof this.import === 'function') {
target = this;
} else {
target = this._findHostApp();
}
target.import('vendor/ember-fetch.js', {
exports: {
default: [
'default',
'Headers',
'Request',
'Response'
]
}
});
},
/*
* Returns a Broccoli tree for the addon's `vendor` directory. The `vendor`
* directory is kind of a junk drawer; nothing we put in it is used unless we
* explicitly `import()` a file (which we do in the `included` hook, above).
*
* To build our tree, we first detect whether we're in a FastBoot build or
* not. Based on that, we return a tree that contains the correct version of
* the polyfill at the `vendor/fetch.js` path.
*/
treeForVendor: function(vendorTree) {
var browserTree = treeForBrowserFetch();
browserTree = map(browserTree, (content) => `if (typeof FastBoot === 'undefined') { ${content} }`);
return browserTree;
},
//If user don't set disableDefaultNodeFetch to be true,
//add node version of fetch.js into fastboot package.json manifest vendorFiles array
updateFastBootManifest: function(manifest) {
if (this._shouldImportDefaultNodeModule()) {
manifest.vendorFiles.push('ember-fetch/fastboot-fetch.js');
}
return manifest;
},
//return host app object
_findHostApp: function() {
// If the addon has the _findHost() method (in ember-cli >= 2.7.0), we'll just
// use that.
let target;
if (typeof this._findHost === 'function') {
target = this._findHost();
}
// Otherwise, we'll use this implementation borrowed from the _findHost()
// method in ember-cli.
// Keep iterating upward until we don't have a grandparent.
// Has to do this grandparent check because at some point we hit the project.
let current = this;
do {
target = current.app || app;
} while (current.parent.parent && (current = current.parent));
return target;
},
//convenient method to determine if we should import the default node fetch module
//or skip. Let consumer app to import node fetch from elsewhere
//return true means we will define fetch from node-fetch
//return false means fetch in node will not be defined, it's user's responsiblity to define their own fetch in fastboot
_shouldImportDefaultNodeModule: function() {
const app = this._findHostApp();
let appOptions = (app && app.options) || {};
//make it backwards compatible for apps doesn't set this config
let shouldDisableNodeFetch = appOptions['ember-fetch'] &&
appOptions['ember-fetch'].disableDefaultNodeFetch === true;
return !shouldDisableNodeFetch;
}
};
// We use a few different Broccoli plugins to build our trees:
//
// broccoli-templater: renders the contents of a file inside a template.
// Used to wrap the browser polyfill in a shim that prevents it from exporting
// a global.
//
// broccoli-funnel: used to import a stub file that requires the node package
// when running in FastBoot.
//
// broccoli-stew: super useful library of Broccoli utilities. We use:
//
// * rename - renames files in a tree
// * find - finds files in a tree based on a glob pattern
var Template = require('broccoli-templater');
var stew = require('broccoli-stew');
var rename = stew.rename;
var find = stew.find;
// Path to the template that contains the shim wrapper around the browser
// polyfill
var templatePath = path.resolve(__dirname + '/assets/browser-fetch.js.t');
// Returns a tree containing the browser polyfill (from
// `node_modules/whatwg-fetch`), wrapped in a shim that stops it from exporting
// a global and instead turns it into a module that can be used by the Ember
// app.
function treeForBrowserFetch() {
var fetchPath = require.resolve('whatwg-fetch');
var expandedFetchPath = expand(fetchPath);
var fetch = normalizeFileName(find(expandedFetchPath));
return new Template(fetch, templatePath, function(content) {
return {
moduleBody: content
};
});
}
// Renames either `fastboot-fetch.js` or `whatwg-fetch/fetch.js` to just
// `ember-fetch.js`. Note that this function will rename _every_ file in the tree;
// we just happen to know that the passed tree only contains a single file.
function normalizeFileName(tree) {
return rename(tree, function() {
return 'ember-fetch.js';
});
}
function expand(input) {
var dirname = path.dirname(input);
var file = path.basename(input);
return dirname + '/{' + file + '}';
}