1 | var util = require('util');
|
2 | var path = require('path');
|
3 | var spawn = require('child_process').spawn;
|
4 | var compInstall = require('./component_install.js');
|
5 | var fs = require('fs');
|
6 |
|
7 | var folderMount = function folderMount(connect, point) {
|
8 | return connect.static(path.resolve(point));
|
9 | };
|
10 |
|
11 | var folderDir = function folderDir(connect, point){
|
12 | return connect.directory(path.resolve(point));
|
13 | }
|
14 |
|
15 | var config = require(__dirname + "/config.json");
|
16 | module.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 |
|
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 |
|
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 |
|
60 | clean: {
|
61 | options:{force:true},
|
62 | dist:['<%= dest %>']
|
63 | },
|
64 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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("\\","/"));
|
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 |
|