UNPKG

13.5 kBJavaScriptView Raw
1var util = require('util');
2var path = require('path');
3var spawn = require('child_process').spawn;
4var compInstall = require('./component_install.js');
5var fs = require('fs');
6
7var folderMount = function folderMount(connect, point) {
8 return connect.static(path.resolve(point));
9};
10
11var folderDir = function folderDir(connect, point){
12 return connect.directory(path.resolve(point));
13}
14
15var config = require(__dirname + "/config.json");
16module.exports = function(grunt){
17
18 var karmaAdapters = __dirname + "/node_modules/grunt-karma/node_modules/karma/adapter";
19 var appJsProd = 'app' + Date.now() + ".js";
20 var appCssProd = 'app' + Date.now() + ".css";
21 var indexTemplate = __dirname + '/index.html';
22 var base = grunt.option('targetBase');
23 var cmd = grunt.option('cmd').toString();
24 process.env.targetBase = base;
25 var destination = grunt.option('destination');
26 var serverPath = grunt.option('server');
27
28 if(grunt.file.exists(base + "/index.html")){
29 indexTemplate = base + "/index.html";
30 }
31 var compyGruntConfig = {
32 pkg: grunt.file.readJSON(base + '/package.json'),
33 dest: destination,
34 targetBase: base,
35 // this is like component.json contents for component
36 componentConfig:{
37 name: '<%= pkg.name %>',
38 main: '<%= pkg.compy.main %>',
39 author: '<%= pkg.author %>',
40 description: '<%= pkg.description %>',
41 dependencies: '<%= pkg.compy.dependencies %>',
42 version: '<%= pkg.version %>',
43 license: '<%= pkg.license %>',
44 scripts:'<%= src.scripts %>',
45 styles: '<%= src.styles %>',
46 images: '<%= src.images %>',
47 fonts: '<%= src.fonts %>',
48 templates: '<%= src.templates %>'
49 },
50 // we-re taking all sources from here
51 src:{
52 scripts:[ base + '{/!(node_modules|dist|components)/**/*.js,/*.js}'],
53 styles:[ base + '{/!(node_modules|dist|components)/**/*.css,/*.css}'],
54 images:[ base+ '/!(node_modules|dist|components)/**/*.{jpg,png,gif,icn}', base+ '/*.{jpg,png,gif,icn}'],
55 fonts:[ base+ '/!(node_modules|dist|components)/**/*.{ttf,eof}', base + '/*.{ttf,eof}'],
56 templates: [ base+ '{/!(node_modules|dist|components)/**/*.html,/*.html}', '!' + base + '/index.html'],
57 tests:[ base + '{/!(node_modules|dist|components)/**/*.spec.js,/*.spec.js}']
58 },
59 // we clean up generated source
60 clean: {
61 options:{force:true},
62 dist:['<%= dest %>']
63 },
64 // we use customized component build grunt task
65 component_constructor:{
66 options:{
67 output:'<%= dest %>',
68 config:'<%= componentConfig %>',
69 base: base,
70 sourceUrls: false
71 },
72 app:{
73 options:{
74 target: 'app',
75 standalone: grunt.option('isStandaloneLib'),
76 configure: function(builder){
77 // we overwrite dependencies to be able to hot component reload while watch
78 var pkg = grunt.file.readJSON(base + '/package.json');
79 if(pkg.compy.dependencies){
80 builder.config.dependencies = pkg.compy.dependencies;
81 }
82 ignoreSources(builder.config, grunt.config('src.tests'));
83 usePlugins(base, builder);
84 }
85 }
86 },
87 test: {
88 options:{
89 configure: function(builder){
90 // we overwrite dependencies to be able to hot component reload while watch
91 var pkg = grunt.file.readJSON(base + '/package.json');
92 if(pkg.compy.dependencies){
93 builder.config.dependencies = pkg.compy.dependencies;
94 }
95 ignoreSources(builder.config);
96 usePlugins(base, builder);
97 }
98 }
99 },
100 styles_dev: {
101 options:{
102 name: 'app',
103 assetType: 'styles',
104 configure: function(builder){
105 // we overwrite dependencies to be able to hot component reload while watch
106 var pkg = grunt.file.readJSON(base + '/package.json');
107 if(pkg.compy.dependencies){
108 builder.config.dependencies = pkg.compy.dependencies;
109 }
110 ignoreSources(builder.config);
111 usePlugins(base, builder);
112 }
113 }
114 },
115 scripts_dev: {
116 options:{
117 name: 'app',
118 assetType: 'scripts',
119 configure: function(builder){
120 // we overwrite dependencies to be able to hot component reload while watch
121 var pkg = grunt.file.readJSON(base + '/package.json');
122 if(pkg.compy.dependencies){
123 builder.config.dependencies = pkg.compy.dependencies;
124 }
125 ignoreSources(builder.config);
126 usePlugins(base, builder);
127 }
128 }
129 },
130 templates_dev: {
131 options:{
132 name: 'app',
133 assetType: 'templates',
134 configure: function(builder){
135 // we overwrite dependencies to be able to hot component reload while watch
136 var pkg = grunt.file.readJSON(base + '/package.json');
137 if(pkg.compy.dependencies){
138 builder.config.dependencies = pkg.compy.dependencies;
139 }
140 ignoreSources(builder.config);
141 usePlugins(base, builder);
142 }
143 }
144 }
145 },
146 watch: {
147 options:{
148 livereload: config.livereloadPort,
149 nospawn: true
150 },
151 // we watch sources independantly, but that doesn't makes much sense
152 js: {
153 files: '<%= src.scripts %>',
154 tasks: ['component_constructor:scripts_dev','concat:dist']
155 },
156 css:{
157 files: '<%= src.styles %>',
158 tasks: ['component_constructor:styles_dev']
159 },
160 html:{
161 files: '<%= src.templates %>',
162 tasks: ['component_constructor:templates_dev','concat:dist']
163 }
164 },
165 connect: {
166 options: {
167 port: 8080,
168 base: '<%= dest %>',
169 hostname: null,
170 },
171 server:{
172 options: {
173 keepalive: false,
174 middleware: function(connect, options){
175 return [
176 require('connect-livereload')({port:config.livereloadPort}),
177 folderMount(connect, destination),
178 folderDir(connect, destination)]
179 }
180 }
181 },
182 alive:{
183 options: {
184 keepalive: true,
185 }
186 }
187 },
188 // preprocess used to build proper index.html
189 preprocess:{
190 html:{
191 options:{
192 context:{
193 name: '<%= pkg.name %>',
194 main: '<%= pkg.compy.main %>',
195 description: '<%= pkg.description %>',
196 title: '<%= pkg.title %>',
197 appdest: 'app.js',
198 appcss: 'app.css'
199 }
200 },
201 src: indexTemplate,
202 dest:'<%= dest %>/index.html'
203 },
204 build:{
205 options:{
206 context:{
207 name: '<%= pkg.name %>',
208 main: '<%= pkg.compy.main %>',
209 description: '<%= pkg.description %>',
210 title: '<%= pkg.title %>',
211 appdest: appJsProd,
212 appcss: appCssProd
213 }
214 },
215 src: indexTemplate,
216 dest:'<%= dest %>/index.html'
217 }
218 },
219 // concat is used to add component runner to the app
220 concat: {
221 dist: {
222 src: ['<%= dest %>/app.js', __dirname + '/tmpl/runner.js'],
223 dest: '<%= dest%>/app.js'
224 }
225 },
226 uglify: {
227 build: {
228 src: ['<%= dest%>/app.js'],
229 dest: '<%= dest%>/' + appJsProd
230 }
231 },
232 cssmin: {
233 build: {
234 src: ['<%= dest%>/app.css'],
235 dest: '<%= dest%>/' + appCssProd
236 }
237 },
238 karma: {
239 unit: {
240 autoWatch:false,
241 browsers:["PhantomJS"],
242 colors: true,
243 configFile: __dirname + '/tmpl/karma.config.js',
244 reporters:['dots'],
245 singleRun: true
246 }
247 }
248 }
249 var matchPlugins = require('./component-plugins-matching.js');
250 matchPlugins(compyGruntConfig, getPlugins(base));
251
252 function usePlugins(baseDir, builder){
253 var plugins = getPlugins(baseDir);
254 plugins.forEach(function(plugin){
255 var pluginModule = require(baseDir + "/node_modules/" + plugin);
256 if(matchPlugins.config[plugin] && matchPlugins.config[plugin].run){
257 return matchPlugins.config[plugin].run(pluginModule, builder);
258 }
259 builder.use(pluginModule);
260 })
261 }
262 /*
263 * getPlugins is getting plugins from users project node_modules folder
264 */
265 function getPlugins(baseDir){
266 var componentPlugins = [];
267 if(!fs.existsSync(baseDir + "/node_modules")) return componentPlugins;
268 var nodeModules = fs.readdirSync(baseDir + "/node_modules");
269 nodeModules.forEach(function(module){
270 if(!/^component-/.test(module)) return;
271 componentPlugins.push(module);
272 });
273 return componentPlugins;
274 }
275
276
277 // this dark magic allows to extend Gruntfiles
278 if(grunt.file.exists(base + '/Gruntfile.js')){
279 var innerGruntfile = require(base + '/Gruntfile.js');
280 var oldInit = grunt.initConfig;
281 var pseudoGrunt = grunt;
282 pseudoGrunt.initConfig = initConfig;
283 function initConfig(configObject){
284 for(var key in configObject){
285 compyGruntConfig[key] = configObject[key];
286 }
287 oldInit.call(this, compyGruntConfig);
288 }
289 innerGruntfile(pseudoGrunt);
290
291 var oldReg = grunt.registerTask
292 grunt.registerTask = function(){
293 if(grunt.task._tasks[arguments[0]]) return;
294 oldReg.apply(this, arguments);
295 }
296 }else{
297 grunt.initConfig(compyGruntConfig);
298 }
299 function ignoreSources(config, ignorePatterns){
300 ['images','fonts','scripts','styles','templates'].forEach(function(asset){
301
302 var ignore = ['components','dist','node_modules'];
303 var testFor = new RegExp('^(' + ignore.join('|') + ')\\/');
304 var ignoreFiles = [];
305 if(ignorePatterns){
306 ignoreFiles = ignoreFiles.concat(grunt.file.expand(ignorePatterns));
307 }
308 var remap = [];
309 if(!config[asset]) return;
310 config[asset].forEach(function(filepath){
311 if(!!~ignoreFiles.indexOf(filepath)) return;
312 var relPath = path.relative(base, filepath);
313 if(testFor.test(relPath)) return;
314 remap.push(relPath.replace("\\","/"));// windows hackin
315 })
316
317 config[asset] = remap;
318 })
319 }
320
321 if(!!~['build','compile','server','test','watch'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-component-constructor/tasks');
322 if(!!~['server'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-contrib-connect/tasks');
323 if(!!~['server','watch'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-contrib-watch/tasks');
324 if(!!~['build','compile'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-contrib-clean/tasks');
325 if(!!~['build','compile'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-preprocess/tasks');
326 if(!!~['build','compile','server'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-contrib-concat/tasks');
327 if(!!~['build'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-contrib-uglify/tasks');
328 if(!!~['build'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-contrib-cssmin/tasks');
329 if(!!~['test'].indexOf(cmd)) grunt.loadTasks(__dirname + '/node_modules/grunt-karma/tasks');
330
331
332 grunt.registerTask('install', 'Install component', function(){
333 var config = grunt.config('componentConfig');
334 ['images','fonts','scripts','styles','templates'].forEach(function(asset){
335 if(config[asset]){
336 config[asset] = grunt.file.expand(config[asset]);
337 }
338 });
339 var done = this.async();
340
341 ignoreSources(config);
342 var args = [];
343
344 var pkgCheck = process.argv.slice(-1)[0].split(':');
345 if(pkgCheck.length > 1){
346 pkgCheck.shift();
347 args = args.concat(pkgCheck);
348 }
349 if(!config.dependencies) config.dependencies = {};
350 compInstall(config, {args: args, out: base + "/components"}, installed);
351
352 function installed(err, deps){
353 var pkg = grunt.file.readJSON(base + '/package.json');
354 pkg.compy.dependencies = deps;
355 grunt.file.write(base + '/package.json', JSON.stringify(pkg, null, 2));
356 done();
357 }
358 })
359
360 grunt.registerTask('generate-tests-runner', function(){
361 var specFiles = grunt.config('src.tests');
362 specFiles = grunt.file.expand(specFiles);
363 var source = "";
364 specFiles.forEach(function(file){
365 var runModule = [path.basename(base), path.relative(base, file)].join('/');
366 source += "require('"+runModule+"');\n";
367 });
368 grunt.file.write(path.normalize(base + '/' + grunt.config('dest') + "/runner.js"), source);
369 })
370
371 grunt.registerTask('server', 'run server', function(arg){
372 if(arg =="watch"){
373 serverPath ? require(serverPath) : grunt.task.run('connect:server');
374 return grunt.task.run('watch');
375 }else{
376 serverPath ? require(serverPath) : grunt.task.run('connect:alive');
377 }
378 });
379
380 grunt.registerTask('compy-compile', ['clean:dist', 'component_constructor:app','concat:dist','preprocess:html']);
381
382 grunt.registerTask('compy-build', ['clean:dist', 'component_constructor:app','concat:dist','preprocess:build', 'uglify', 'cssmin']);
383
384 grunt.registerTask('compy-test', ['clean:dist', 'component_constructor:test','generate-tests-runner' ,'karma'])
385
386 grunt.registerTask('compile', ['compy-compile']);
387
388 grunt.registerTask('build', ['compy-build']);
389
390 grunt.registerTask('test', ['compy-test']);
391
392 grunt.registerTask('default',['compile'])
393}
394