088d10e1aec247ca182d629f01d91b5a822fd7c6
[Packages/TYPO3.CMS.git] / Build / Gruntfile.js
1 /*
2 * This file is part of the TYPO3 CMS project.
3 *
4 * It is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License, either version 2
6 * of the License, or any later version.
7 *
8 * For the full copyright and license information, please read the
9 * LICENSE.txt file that was distributed with this source code.
10 *
11 * The TYPO3 project - inspiring people to share!
12 */
13
14 module.exports = function (grunt) {
15
16 /**
17 * Grunt stylefmt task
18 */
19 grunt.registerMultiTask('formatsass', 'Grunt task for stylefmt', function () {
20 var options = this.options(),
21 done = this.async(),
22 stylefmt = require('stylefmt'),
23 scss = require('postcss-scss'),
24 files = this.filesSrc.filter(function (file) {
25 return grunt.file.isFile(file);
26 }),
27 counter = 0;
28 this.files.forEach(function (file) {
29 file.src.filter(function (filepath) {
30 var content = grunt.file.read(filepath);
31 var settings = {
32 from: filepath,
33 syntax: scss
34 };
35 stylefmt.process(content, settings).then(function (result) {
36 grunt.file.write(file.dest, result.css);
37 grunt.log.success('Source file "' + filepath + '" was processed.');
38 counter++;
39 if (counter >= files.length) done(true);
40 });
41 });
42 });
43 });
44
45 // Project configuration.
46 grunt.initConfig({
47 pkg: grunt.file.readJSON('package.json'),
48 paths: {
49 resources: 'Resources/',
50 sass: '<%= paths.resources %>Public/Sass/',
51 root: '../',
52 sysext: '<%= paths.root %>typo3/sysext/',
53 form: '<%= paths.sysext %>form/Resources/',
54 frontend: '<%= paths.sysext %>frontend/Resources/',
55 install: '<%= paths.sysext %>install/Resources/',
56 linkvalidator: '<%= paths.sysext %>linkvalidator/Resources/',
57 backend: '<%= paths.sysext %>backend/Resources/',
58 t3editor: '<%= paths.sysext %>t3editor/Resources/',
59 workspaces: '<%= paths.sysext %>workspaces/Resources/',
60 ckeditor: '<%= paths.sysext %>rte_ckeditor/Resources/',
61 core: '<%= paths.sysext %>core/Resources/',
62 bower: 'bower_components/',
63 flags: '<%= paths.bower %>region-flags/svg/',
64 t3icons: '<%= paths.bower %>typo3-icons/dist/',
65 npm: 'node_modules/'
66 },
67 stylelint: {
68 options: {
69 configFile: '<%= paths.root %>.stylelintrc',
70 },
71 sass: ['<%= paths.sass %>**/*.scss']
72 },
73 formatsass: {
74 sass: {
75 files: [{
76 expand: true,
77 cwd: '<%= paths.sass %>',
78 src: ['**/*.scss'],
79 dest: '<%= paths.sass %>'
80 }]
81 }
82 },
83 sass: {
84 options: {
85 outputStyle: 'expanded',
86 precision: 8,
87 includePaths: [
88 'bower_components/bootstrap-sass/assets/stylesheets',
89 'bower_components/fontawesome/scss',
90 'bower_components/eonasdan-bootstrap-datetimepicker/src/sass',
91 'node_modules/tagsort'
92 ]
93 },
94 backend: {
95 files: {
96 "<%= paths.backend %>Public/Css/backend.css": "<%= paths.sass %>backend.scss"
97 }
98 },
99 core: {
100 files: {
101 "<%= paths.core %>Public/Css/errorpage.css": "<%= paths.sass %>errorpage.scss"
102 }
103 },
104 form: {
105 files: {
106 "<%= paths.form %>Public/Css/form.css": "<%= paths.sass %>form.scss"
107 }
108 },
109 frontend: {
110 files: {
111 "<%= paths.frontend %>Public/Css/adminpanel.css": "<%= paths.sass %>adminpanel.scss"
112 }
113 },
114 install: {
115 files: {
116 "<%= paths.install %>Public/Css/install.css": "<%= paths.sass %>install.scss"
117 }
118 },
119 linkvalidator: {
120 files: {
121 "<%= paths.linkvalidator %>Public/Css/linkvalidator.css": "<%= paths.sass %>linkvalidator.scss"
122 }
123 },
124 workspaces: {
125 files: {
126 "<%= paths.workspaces %>Public/Css/preview.css": "<%= paths.sass %>workspace.scss"
127 }
128 },
129 t3editor: {
130 files: {
131 '<%= paths.t3editor %>Public/Css/t3editor.css': '<%= paths.sass %>editor.scss',
132 '<%= paths.t3editor %>Public/Css/t3editor_inner.css': '<%= paths.sass %>editor_inner.scss',
133 '<%= paths.t3editor %>Public/Css/t3editor_typoscript_colors.css': '<%= paths.sass %>editor_typoscript_colors.scss'
134 }
135 }
136 },
137 postcss: {
138 options: {
139 map: false,
140 processors: [
141 require('autoprefixer')({
142 browsers: [
143 'Chrome >= 57',
144 'Firefox >= 52',
145 'Edge >= 14',
146 'Explorer >= 11',
147 'iOS >= 9',
148 'Safari >= 8',
149 'Android >= 4',
150 'Opera >= 43'
151 ]
152 }),
153 require('postcss-clean')({
154 keepSpecialComments: 0
155 }),
156 require('postcss-banner')({
157 banner: 'This file is part of the TYPO3 CMS project.\n' +
158 '\n' +
159 'It is free software; you can redistribute it and/or modify it under\n' +
160 'the terms of the GNU General Public License, either version 2\n' +
161 'of the License, or any later version.\n' +
162 '\n' +
163 'For the full copyright and license information, please read the\n' +
164 'LICENSE.txt file that was distributed with this source code.\n' +
165 '\n' +
166 'The TYPO3 project - inspiring people to share!',
167 important: true,
168 inline: false
169 })
170 ]
171 },
172 backend: {
173 src: '<%= paths.backend %>Public/Css/*.css'
174 },
175 core: {
176 src: '<%= paths.core %>Public/Css/*.css'
177 },
178 form: {
179 src: '<%= paths.form %>Public/Css/*.css'
180 },
181 frontend: {
182 src: '<%= paths.frontend %>Public/Css/*.css'
183 },
184 install: {
185 src: '<%= paths.install %>Public/Css/*.css'
186 },
187 linkvalidator: {
188 src: '<%= paths.linkvalidator %>Public/Css/*.css'
189 },
190 t3editor: {
191 src: '<%= paths.t3editor %>Public/Css/*.css'
192 },
193 workspaces: {
194 src: '<%= paths.workspaces %>Public/Css/*.css'
195 }
196 },
197 ts: {
198 default: {
199 tsconfig: true,
200 options: {
201 verbose: false,
202 additionalFlags: '--typeRoots "node_modules/@types,types"'
203 }
204 }
205 },
206 tslint: {
207 options: {
208 configuration: 'tslint.json',
209 force: false
210 },
211 files: {
212 src: [
213 '<%= paths.sysext %>*/Resources/Private/TypeScript/**/*.ts'
214 ]
215 }
216 },
217 watch: {
218 options: {
219 livereload: true
220 },
221 sass: {
222 files: '<%= paths.sass %>**/*.scss',
223 tasks: 'css'
224 },
225 ts: {
226 files: '<%= paths.sysext %>*/Resources/Private/TypeScript/**/*.ts',
227 tasks: 'scripts'
228 }
229 },
230 copy: {
231 options: {
232 punctuation: ''
233 },
234 ts_files: {
235 files: [{
236 expand: true,
237 cwd: '<%= paths.root %>Build/JavaScript/typo3/sysext/',
238 src: ['**/*.js', '**/*.js.map'],
239 dest: '<%= paths.sysext %>',
240 rename: function (dest, src) {
241 return dest + src.replace('Resources/Private/TypeScript', 'Resources/Public/JavaScript');
242 }
243 }]
244 },
245 core_icons: {
246 files: [{
247 expand: true,
248 cwd: '<%= paths.t3icons %>',
249 src: ['**/*.svg', '!module/*'],
250 dest: '<%= paths.sysext %>core/Resources/Public/Icons/T3Icons/',
251 ext: '.svg'
252 }]
253 },
254 module_icons: {
255 files: [
256 {
257 dest: '<%= paths.sysext %>about/Resources/Public/Icons/module-about.svg',
258 src: '<%= paths.t3icons %>module/module-about.svg'
259 },
260 {
261 dest: '<%= paths.sysext %>belog/Resources/Public/Icons/module-belog.svg',
262 src: '<%= paths.t3icons %>module/module-belog.svg'
263 },
264 {
265 dest: '<%= paths.sysext %>beuser/Resources/Public/Icons/module-beuser.svg',
266 src: '<%= paths.t3icons %>module/module-beuser.svg'
267 },
268 {
269 dest: '<%= paths.sysext %>lowlevel/Resources/Public/Icons/module-config.svg',
270 src: '<%= paths.t3icons %>module/module-config.svg'
271 },
272 {
273 dest: '<%= paths.sysext %>cshmanual/Resources/Public/Icons/module-cshmanual.svg',
274 src: '<%= paths.t3icons %>module/module-cshmanual.svg'
275 },
276 {
277 dest: '<%= paths.sysext %>lowlevel/Resources/Public/Icons/module-dbint.svg',
278 src: '<%= paths.t3icons %>module/module-dbint.svg'
279 },
280 {
281 dest: '<%= paths.sysext %>documentation/Resources/Public/Icons/module-documentation.svg',
282 src: '<%= paths.t3icons %>module/module-documentation.svg'
283 },
284 {
285 dest: '<%= paths.sysext %>extensionmanager/Resources/Public/Icons/module-extensionmanager.svg',
286 src: '<%= paths.t3icons %>module/module-extensionmanager.svg'
287 },
288 {
289 dest: '<%= paths.sysext %>filelist/Resources/Public/Icons/module-filelist.svg',
290 src: '<%= paths.t3icons %>module/module-filelist.svg'
291 },
292 {
293 dest: '<%= paths.sysext %>form/Resources/Public/Icons/module-form.svg',
294 src: '<%= paths.t3icons %>module/module-form.svg'
295 },
296 {
297 dest: '<%= paths.sysext %>func/Resources/Public/Icons/module-func.svg',
298 src: '<%= paths.t3icons %>module/module-func.svg'
299 },
300 {
301 dest: '<%= paths.sysext %>indexed_search/Resources/Public/Icons/module-indexed_search.svg',
302 src: '<%= paths.t3icons %>module/module-indexed_search.svg'
303 },
304 {
305 dest: '<%= paths.sysext %>info/Resources/Public/Icons/module-info.svg',
306 src: '<%= paths.t3icons %>module/module-info.svg'
307 },
308 {
309 dest: '<%= paths.sysext %>install/Resources/Public/Icons/module-install.svg',
310 src: '<%= paths.t3icons %>module/module-install.svg'
311 },
312 {
313 dest: '<%= paths.sysext %>lang/Resources/Public/Icons/module-lang.svg',
314 src: '<%= paths.t3icons %>module/module-lang.svg'
315 },
316 {
317 dest: '<%= paths.sysext %>recordlist/Resources/Public/Icons/module-list.svg',
318 src: '<%= paths.t3icons %>module/module-list.svg'
319 },
320 {
321 dest: '<%= paths.sysext %>backend/Resources/Public/Icons/module-page.svg',
322 src: '<%= paths.t3icons %>module/module-page.svg'
323 },
324 {
325 dest: '<%= paths.sysext %>beuser/Resources/Public/Icons/module-permission.svg',
326 src: '<%= paths.t3icons %>module/module-permission.svg'
327 },
328 {
329 dest: '<%= paths.sysext %>recycler/Resources/Public/Icons/module-recycler.svg',
330 src: '<%= paths.t3icons %>module/module-recycler.svg'
331 },
332 {
333 dest: '<%= paths.sysext %>reports/Resources/Public/Icons/module-reports.svg',
334 src: '<%= paths.t3icons %>module/module-reports.svg'
335 },
336 {
337 dest: '<%= paths.sysext %>scheduler/Resources/Public/Icons/module-scheduler.svg',
338 src: '<%= paths.t3icons %>module/module-scheduler.svg'
339 },
340 {
341 dest: '<%= paths.sysext %>setup/Resources/Public/Icons/module-setup.svg',
342 src: '<%= paths.t3icons %>module/module-setup.svg'
343 },
344 {
345 dest: '<%= paths.sysext %>taskcenter/Resources/Public/Icons/module-taskcenter.svg',
346 src: '<%= paths.t3icons %>module/module-taskcenter.svg'
347 },
348 {
349 dest: '<%= paths.sysext %>tstemplate/Resources/Public/Icons/module-tstemplate.svg',
350 src: '<%= paths.t3icons %>module/module-tstemplate.svg'
351 },
352 {
353 dest: '<%= paths.sysext %>version/Resources/Public/Icons/module-version.svg',
354 src: '<%= paths.t3icons %>module/module-version.svg'
355 },
356 {
357 dest: '<%= paths.sysext %>viewpage/Resources/Public/Icons/module-viewpage.svg',
358 src: '<%= paths.t3icons %>module/module-viewpage.svg'
359 },
360 {
361 dest: '<%= paths.sysext %>workspaces/Resources/Public/Icons/module-workspaces.svg',
362 src: '<%= paths.t3icons %>module/module-workspaces.svg'
363 }
364 ]
365 },
366 extension_icons: {
367 files: [
368 {
369 dest: '<%= paths.sysext %>form/Resources/Public/Icons/Extension.svg',
370 src: '<%= paths.t3icons %>module/module-form.svg'
371 }
372 ]
373 },
374 fonts: {
375 files: [
376 {
377 dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.eot',
378 src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.eot'
379 },
380 {
381 dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.svg',
382 src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.svg'
383 },
384 {
385 dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.ttf',
386 src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.ttf'
387 },
388 {
389 dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.woff',
390 src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.woff'
391 },
392 {
393 dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.woff2',
394 src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.woff2'
395 }
396 ]
397 }
398 },
399 bowercopy: {
400 options: {
401 clean: false,
402 report: false,
403 runBower: false,
404 srcPrefix: "bower_components/"
405 },
406 glob: {
407 files: {
408 // When using glob patterns, destinations are *always* folder names
409 // into which matching files will be copied
410 // Also note that subdirectories are **not** maintained
411 // if a destination is specified
412 // For example, one of the files copied here is
413 // 'lodash/dist/lodash.js' -> 'public/js/libs/lodash/lodash.js'
414 '<%= paths.sysext %>core/Resources/Public/Images/colorpicker': 'jquery-minicolors/*.png'
415 }
416 },
417 ckeditor: {
418 options: {
419 destPrefix: "<%= paths.ckeditor %>Public/JavaScript/Contrib"
420 },
421 files: {
422 'ckeditor.js': 'ckeditor/ckeditor.js',
423 'plugins/': 'ckeditor/plugins/',
424 'skins/': 'ckeditor/skins/',
425 'lang/': 'ckeditor/lang/'
426 }
427 },
428 all: {
429 options: {
430 destPrefix: "<%= paths.core %>Public/JavaScript/Contrib"
431 },
432 files: {
433 'nprogress.js': 'nprogress/nprogress.js',
434 'jquery.matchHeight-min.js': 'matchHeight/dist/jquery.matchHeight-min.js',
435 'jquery.dataTables.js': 'datatables/media/js/jquery.dataTables.min.js',
436 'require.js': 'requirejs/require.js',
437 'moment.js': 'moment/min/moment-with-locales.min.js',
438 'moment-timezone.js': 'moment-timezone/builds/moment-timezone-with-data.min.js',
439 'cropper.min.js': 'cropper/dist/cropper.min.js',
440 'imagesloaded.pkgd.min.js': 'imagesloaded/imagesloaded.pkgd.min.js',
441 'bootstrap-datetimepicker.js': 'eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js',
442 'autosize.js': 'autosize/dist/autosize.min.js',
443 'taboverride.min.js': 'taboverride/build/output/taboverride.min.js',
444 'bootstrap-slider.min.js': 'seiyria-bootstrap-slider/dist/bootstrap-slider.min.js',
445 /* disabled until events are not bound to document only
446 see https://github.com/claviska/jquery-minicolors/issues/192
447 see https://github.com/claviska/jquery-minicolors/issues/206
448 'jquery.minicolors.js': 'jquery-minicolors/jquery.minicolors.min.js',
449 */
450 /* disabled until autocomplete formatGroup is fixed to pass on the index too
451 'jquery.autocomplete.js': 'devbridge-autocomplete/src/jquery.autocomplete.js',
452 */
453 'd3/d3.js': 'd3/d3.min.js',
454 /**
455 * copy needed parts of jquery
456 */
457 'jquery/jquery-3.2.1.js': 'jquery/dist/jquery.js',
458 'jquery/jquery-3.2.1.min.js': 'jquery/dist/jquery.min.js',
459 /**
460 * copy needed parts of jquery-ui
461 */
462 'jquery-ui/core.js': 'jquery-ui/ui/core.js',
463 'jquery-ui/draggable.js': 'jquery-ui/ui/draggable.js',
464 'jquery-ui/droppable.js': 'jquery-ui/ui/droppable.js',
465 'jquery-ui/mouse.js': 'jquery-ui/ui/mouse.js',
466 'jquery-ui/position.js': 'jquery-ui/ui/position.js',
467 'jquery-ui/resizable.js': 'jquery-ui/ui/resizable.js',
468 'jquery-ui/selectable.js': 'jquery-ui/ui/selectable.js',
469 'jquery-ui/sortable.js': 'jquery-ui/ui/sortable.js',
470 'jquery-ui/widget.js': 'jquery-ui/ui/widget.js'
471 }
472 }
473 },
474 uglify: {
475 thirdparty: {
476 files: {
477 "<%= paths.core %>Public/JavaScript/Contrib/require.js": ["<%= paths.core %>Public/JavaScript/Contrib/require.js"],
478 "<%= paths.core %>Public/JavaScript/Contrib/nprogress.js": ["<%= paths.core %>Public/JavaScript/Contrib/nprogress.js"],
479 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/core.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/core.js"],
480 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/draggable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/draggable.js"],
481 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/droppable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/droppable.js"],
482 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/mouse.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/mouse.js"],
483 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/position.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/position.js"],
484 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/resizable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/resizable.js"],
485 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/selectable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/selectable.js"],
486 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/sortable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/sortable.js"],
487 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/widget.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/widget.js"],
488 "<%= paths.install %>Public/JavaScript/chosen.jquery.min.js": ["<%= paths.npm %>chosen-js/chosen.jquery.js"],
489 "<%= paths.core %>Public/JavaScript/Contrib/bootstrap-datetimepicker.js": ["<%= paths.core %>Public/JavaScript/Contrib/bootstrap-datetimepicker.js"]
490 }
491 }
492 },
493 svgmin: {
494 options: {
495 plugins: [
496 {removeViewBox: false}
497 ]
498 },
499 // Flags
500 flags: {
501 files: [{
502 expand: true,
503 cwd: '<%= paths.flags %>',
504 src: '*.svg',
505 dest: '<%= paths.sysext %>core/Resources/Public/Icons/Flags/SVG/',
506 ext: '.svg',
507 extDot: 'first'
508 }]
509 }
510 }
511 });
512
513 // Register tasks
514 grunt.loadNpmTasks('grunt-sass');
515 grunt.loadNpmTasks('grunt-contrib-watch');
516 grunt.loadNpmTasks('grunt-bowercopy');
517 grunt.loadNpmTasks('grunt-npm-install');
518 grunt.loadNpmTasks('grunt-bower-just-install');
519 grunt.loadNpmTasks('grunt-contrib-uglify');
520 grunt.loadNpmTasks('grunt-svgmin');
521 grunt.loadNpmTasks('grunt-postcss');
522 grunt.loadNpmTasks('grunt-contrib-copy');
523 grunt.loadNpmTasks("grunt-ts");
524 grunt.loadNpmTasks('grunt-tslint');
525 grunt.loadNpmTasks('grunt-stylelint');
526
527 /**
528 * grunt default task
529 *
530 * call "$ grunt"
531 *
532 * this will trigger the CSS build
533 */
534 grunt.registerTask('default', ['css']);
535
536 /**
537 * grunt lint
538 *
539 * call "$ grunt lint"
540 *
541 * this task does the following things:
542 * - tslint
543 * - stylelint
544 */
545 grunt.registerTask('lint', ['tslint', 'stylelint']);
546
547 /**
548 * grunt format
549 *
550 * call "$ grunt format"
551 *
552 * this task does the following things:
553 * - formatsass
554 * - lint
555 */
556 grunt.registerTask('format', ['formatsass', 'stylelint']);
557
558 /**
559 * grunt css task
560 *
561 * call "$ grunt css"
562 *
563 * this task does the following things:
564 * - sass
565 * - postcss
566 */
567 grunt.registerTask('css', ['sass', 'postcss']);
568
569 /**
570 * grunt update task
571 *
572 * call "$ grunt update"
573 *
574 * this task does the following things:
575 * - npm install
576 * - bower install
577 * - copy some bower components to a specific destinations because they need to be included via PHP
578 */
579 grunt.registerTask('update', ['npm-install', 'bower_install', 'bowercopy']);
580
581 /**
582 * grunt scripts task
583 *
584 * call "$ grunt scripts"
585 *
586 * this task does the following things:
587 * - 1) Check all TypeScript files (*.ts) with TSLint which are located in sysext/<EXTKEY>/Resources/Private/TypeScript/*.ts
588 * - 2) Compiles all TypeScript files (*.ts) which are located in sysext/<EXTKEY>/Resources/Private/TypeScript/*.ts
589 * - 3) Copy all generated JavaScript and Map files to public folders
590 */
591 grunt.registerTask('scripts', ['tslint', 'tsclean', 'ts', 'copy:ts_files']);
592
593 grunt.task.registerTask('tsclean', function () {
594 grunt.option('force');
595 grunt.file.delete("JavaScript");
596 });
597
598 /**
599 * grunt build task
600 *
601 * call "$ grunt build"
602 *
603 * this task does the following things:
604 * - execute update task
605 * - execute copy task
606 * - compile sass files
607 * - uglify js files
608 * - minifies svg files
609 * - compiles TypeScript files
610 */
611 grunt.registerTask('build', ['update', 'scripts', 'copy', 'format', 'css', 'uglify', 'svgmin']);
612 };