UNPKG

7.14 kBJavaScriptView Raw
1var _ = require('underscore'),
2 path = require('path');
3const corePlugins = [
4 'mixin',
5 'styles-output', 'scripts-output', 'static-output',
6 'scope', 'router', 'template', 'inline-styles',
7 'coffee-script', 'stylus', 'handlebars',
8 'module-map', 'package-config', 'stylus-config',
9 'update-externals',
10 'server-scripts',
11 'inline-styles-resources', 'styles', 'scripts', 'static'
12];
13var fileUtils = require("./fileUtil");
14
15var globalPlugins = {};
16
17exports.plugin = function(name, plugin) {
18 globalPlugins[name] = plugin;
19 plugin.id = name;
20};
21
22exports.plugin('module-map', require('./plugins/module-map'));
23exports.plugin('package-config', require('./plugins/package-config'));
24exports.plugin('router', require('./plugins/router'));
25exports.plugin('scope', require('./plugins/scope'));
26exports.plugin('stylus', require('./plugins/stylus'));
27exports.plugin('stylus-config', require('./plugins/stylus-config'));
28exports.plugin('coffee-script', require('./plugins/coffee-script'));
29exports.plugin('handlebars', require('./plugins/handlebars'));
30exports.plugin('inline-styles', require('./plugins/inline-styles'));
31exports.plugin('inline-styles-resources', require('./plugins/inline-styles-resources'));
32exports.plugin('mixin', require('./plugins/mixin'));
33exports.plugin('update-externals', require('./plugins/update-externals'));
34exports.plugin('template', require('./plugins/template'));
35exports.plugin('styles', require('./plugins/styles.js'));
36exports.plugin('server-scripts', require('./plugins/server-scripts.js'));
37exports.plugin('scripts', require('./plugins/scripts.js'));
38exports.plugin('static', require('./plugins/static.js'));
39exports.plugin('styles-output', require('./plugins/styles-output.js'));
40exports.plugin('scripts-output', require('./plugins/scripts-output.js'));
41exports.plugin('static-output', require('./plugins/static-output.js'));
42
43exports.create = function(options) {
44 var plugins;
45 var modes; // all registered modes
46 var pluginModes; // map of modes and plugins scoped to the mode
47 var modeAll; // plugins that are scoped to all modes
48
49 function runPlugins(context, methodName, complete, failOver, noMode) {
50 var len = 0,
51 pluginMode = pluginModes[context.mode] || [];
52
53 return (function next(complete) {
54 /*jshint boss:true */
55 var plugin;
56 while (plugin = plugins[len++]) {
57 // if plugin shouldn't work with current mode, go to next
58 if (!noMode
59 && (!context.mode || pluginMode.indexOf(plugin) < 0)
60 && modeAll.indexOf(plugin) < 0) {
61 continue;
62 }
63
64 var method = plugin[methodName];
65 if (method) {
66 if (complete) {
67 process.nextTick(function() {
68 method.call(plugin, context, next, complete);
69 });
70 return;
71 } else {
72 return method.call(plugin, context, next, complete);
73 }
74 }
75 }
76
77 // We're done, send data back
78 if (complete) {
79 // async
80 // Clear out our stack under async mode to try to keep the stack somewhat sane.
81 process.nextTick(function() {
82 complete(undefined, failOver && failOver());
83 });
84 } else {
85 // sync
86 return failOver && failOver();
87 }
88 })(complete);
89 }
90
91 function registerPlugin(plugin) {
92 var _plugin = globalPlugins[plugin] || plugin;
93
94 var mode = _plugin.mode;
95 if (mode) {
96 if (_.isString(mode)) {
97 mode = [mode];
98 }
99 _.each(mode, function(_mode) {
100 if (mode === 'all') {
101 // allow plugins to contribute new modes and participate in all modes
102 modeAll.push(_plugin);
103 } else {
104 if (modes.indexOf(_mode) < 0) {
105 modes.push(_mode);
106 pluginModes[_mode] = [];
107 }
108 pluginModes[_mode].push(_plugin);
109 }
110 });
111 } else {
112 modeAll.push(_plugin);
113 }
114 plugins.push(_plugin);
115 plugins.sort(function(a, b) {
116 return (a.priority || 50) - (b.priority || 50);
117 });
118 }
119
120 return {
121 get: function(name) {
122 // Find the plugin with this id, if one exists
123 var plugin = plugins.reduce(function(plugin, left) {
124 return plugin.id === name ? plugin : left;
125 });
126
127 // If the plugin was not found do not return the last item in the reduce
128 if (plugin.id === name) {
129 return plugin;
130 }
131 },
132 use: function(plugin) {
133 if (plugin.path || (_.isString(plugin) && !globalPlugins[plugin])) {
134 var pluginPath = plugin.path || plugin;
135 var options = plugin.options;
136 try {
137 plugin = require(pluginPath);
138 } catch (e) {
139 plugin = require(path.resolve(process.cwd(), fileUtils.lookupPath()) + '/node_modules/' + pluginPath);
140 }
141 if ('function' === typeof plugin) {
142 plugin = plugin(options);
143 }
144 }
145 registerPlugin(plugin);
146 },
147
148 initialize: function(config) {
149 // reset
150 plugins = [];
151 modes = []; // all registered modes
152 pluginModes = {}; // map of modes and plugins scoped to the mode
153 modeAll = []; // plugins that are scoped to all modes
154
155 // load the core plugins
156 if (!options.ignoreCorePlugins) {
157 corePlugins.forEach(registerPlugin);
158 }
159
160 var self = this;
161 function plugin(plugins) {
162 if (plugins) {
163 plugins.forEach(self.use, self);
164 }
165 }
166
167 // load command line plugins
168 plugin(options.plugins);
169
170 // load lumbar.json plugins
171 plugin(config.attributes.plugins);
172 },
173
174 loadMixin: function(context, complete) {
175 runPlugins(context, 'loadMixin', complete, undefined, true);
176 },
177 loadConfig: function(context, complete) {
178 runPlugins(context, 'loadConfig', complete, undefined, true);
179 },
180 outputConfigs: function(context, complete) {
181 runPlugins(context, 'outputConfigs', complete, function() {
182 // Default to a one to one mapping for a given {platform, package, module, mode} combo
183 return [ {} ];
184 });
185 },
186 modeComplete: function(context, complete) {
187 runPlugins(context, 'modeComplete', complete);
188 },
189 fileName: function(context, complete) {
190 runPlugins(context, 'fileName', complete);
191 },
192
193 fileFilter: function(context) {
194 return runPlugins(context, 'fileFilter');
195 },
196 moduleResources: function(context, complete) {
197 runPlugins(context, 'moduleResources', complete, function() {
198 var module = context.module;
199 return (module[context.mode] || []).slice();
200 });
201 },
202 resourceList: function(context, complete) {
203 runPlugins(context, 'resourceList', complete, function() { return [context.resource]; });
204 },
205
206 file: function(context, complete) {
207 runPlugins(context, 'file', complete);
208 },
209 module: function(context, complete) {
210 runPlugins(context, 'module', complete);
211 },
212 resource: function(context, complete) {
213 runPlugins(context, 'resource', complete, function() { return context.resource; });
214 },
215 modes: function() {
216 return modes;
217 }
218 };
219};