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