06c4c34799860fdb1dd7a16eff827a9eee267637
[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 }
202 }
203 },
204 tslint: {
205 options: {
206 configuration: 'tslint.json',
207 force: false
208 },
209 files: {
210 src: [
211 '<%= paths.sysext %>*/Resources/Private/TypeScript/**/*.ts'
212 ]
213 }
214 },
215 watch: {
216 options: {
217 livereload: true
218 },
219 sass: {
220 files: '<%= paths.sass %>**/*.scss',
221 tasks: 'css'
222 },
223 ts: {
224 files: '<%= paths.sysext %>*/Resources/Private/TypeScript/**/*.ts',
225 tasks: 'scripts'
226 }
227 },
228 copy: {
229 options: {
230 punctuation: ''
231 },
232 ts_files: {
233 files: [{
234 expand: true,
235 cwd: '<%= paths.root %>Build/JavaScript/typo3/sysext/',
236 src: ['**/*.js', '**/*.js.map'],
237 dest: '<%= paths.sysext %>',
238 rename: function(dest, src) {
239 return dest + src.replace('Resources/Private/TypeScript', 'Resources/Public/JavaScript');
240 }
241 }]
242 },
243 core_icons: {
244 files: [{
245 expand: true,
246 cwd: '<%= paths.t3icons %>',
247 src: ['**/*.svg', '!module/*'],
248 dest: '<%= paths.sysext %>core/Resources/Public/Icons/T3Icons/',
249 ext: '.svg'
250 }]
251 },
252 module_icons: {
253 files: [
254 { dest: '<%= paths.sysext %>about/Resources/Public/Icons/module-about.svg', src: '<%= paths.t3icons %>module/module-about.svg' },
255 { dest: '<%= paths.sysext %>belog/Resources/Public/Icons/module-belog.svg', src: '<%= paths.t3icons %>module/module-belog.svg' },
256 { dest: '<%= paths.sysext %>beuser/Resources/Public/Icons/module-beuser.svg', src: '<%= paths.t3icons %>module/module-beuser.svg' },
257 { dest: '<%= paths.sysext %>lowlevel/Resources/Public/Icons/module-config.svg', src: '<%= paths.t3icons %>module/module-config.svg' },
258 { dest: '<%= paths.sysext %>cshmanual/Resources/Public/Icons/module-cshmanual.svg', src: '<%= paths.t3icons %>module/module-cshmanual.svg' },
259 { dest: '<%= paths.sysext %>lowlevel/Resources/Public/Icons/module-dbint.svg', src: '<%= paths.t3icons %>module/module-dbint.svg' },
260 { dest: '<%= paths.sysext %>documentation/Resources/Public/Icons/module-documentation.svg', src: '<%= paths.t3icons %>module/module-documentation.svg' },
261 { dest: '<%= paths.sysext %>extensionmanager/Resources/Public/Icons/module-extensionmanager.svg', src: '<%= paths.t3icons %>module/module-extensionmanager.svg' },
262 { dest: '<%= paths.sysext %>filelist/Resources/Public/Icons/module-filelist.svg', src: '<%= paths.t3icons %>module/module-filelist.svg' },
263 { dest: '<%= paths.sysext %>form/Resources/Public/Icons/module-form.svg', src: '<%= paths.t3icons %>module/module-form.svg' },
264 { dest: '<%= paths.sysext %>func/Resources/Public/Icons/module-func.svg', src: '<%= paths.t3icons %>module/module-func.svg' },
265 { dest: '<%= paths.sysext %>indexed_search/Resources/Public/Icons/module-indexed_search.svg', src: '<%= paths.t3icons %>module/module-indexed_search.svg' },
266 { dest: '<%= paths.sysext %>info/Resources/Public/Icons/module-info.svg', src: '<%= paths.t3icons %>module/module-info.svg' },
267 { dest: '<%= paths.sysext %>install/Resources/Public/Icons/module-install.svg', src: '<%= paths.t3icons %>module/module-install.svg' },
268 { dest: '<%= paths.sysext %>lang/Resources/Public/Icons/module-lang.svg', src: '<%= paths.t3icons %>module/module-lang.svg' },
269 { dest: '<%= paths.sysext %>recordlist/Resources/Public/Icons/module-list.svg', src: '<%= paths.t3icons %>module/module-list.svg' },
270 { dest: '<%= paths.sysext %>backend/Resources/Public/Icons/module-page.svg', src: '<%= paths.t3icons %>module/module-page.svg' },
271 { dest: '<%= paths.sysext %>beuser/Resources/Public/Icons/module-permission.svg', src: '<%= paths.t3icons %>module/module-permission.svg' },
272 { dest: '<%= paths.sysext %>recycler/Resources/Public/Icons/module-recycler.svg', src: '<%= paths.t3icons %>module/module-recycler.svg' },
273 { dest: '<%= paths.sysext %>reports/Resources/Public/Icons/module-reports.svg', src: '<%= paths.t3icons %>module/module-reports.svg' },
274 { dest: '<%= paths.sysext %>scheduler/Resources/Public/Icons/module-scheduler.svg', src: '<%= paths.t3icons %>module/module-scheduler.svg' },
275 { dest: '<%= paths.sysext %>setup/Resources/Public/Icons/module-setup.svg', src: '<%= paths.t3icons %>module/module-setup.svg' },
276 { dest: '<%= paths.sysext %>taskcenter/Resources/Public/Icons/module-taskcenter.svg', src: '<%= paths.t3icons %>module/module-taskcenter.svg' },
277 { dest: '<%= paths.sysext %>tstemplate/Resources/Public/Icons/module-tstemplate.svg', src: '<%= paths.t3icons %>module/module-tstemplate.svg' },
278 { dest: '<%= paths.sysext %>version/Resources/Public/Icons/module-version.svg', src: '<%= paths.t3icons %>module/module-version.svg' },
279 { dest: '<%= paths.sysext %>viewpage/Resources/Public/Icons/module-viewpage.svg', src: '<%= paths.t3icons %>module/module-viewpage.svg' },
280 { dest: '<%= paths.sysext %>workspaces/Resources/Public/Icons/module-workspaces.svg', src: '<%= paths.t3icons %>module/module-workspaces.svg' }
281 ]
282 },
283 extension_icons: {
284 files: [
285 { dest: '<%= paths.sysext %>form/Resources/Public/Icons/Extension.svg', src: '<%= paths.t3icons %>module/module-form.svg' }
286 ]
287 },
288 fonts: {
289 files: [
290 { dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.eot', src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.eot' },
291 { dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.svg', src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.svg' },
292 { dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.ttf', src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.ttf' },
293 { dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.woff', src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.woff' },
294 { dest: '<%= paths.sysext %>backend/Resources/Public/Fonts/FontAwesome/fontawesome-webfont.woff2', src: '<%= paths.bower %>fontawesome/fonts/fontawesome-webfont.woff2' }
295 ]
296 },
297 npm: {
298 files: [
299 {dest: '<%= paths.install %>Public/JavaScript/chosen.jquery.js', src: '<%= paths.npm %>chosen-js/chosen.jquery.js'}
300 ]
301 }
302 },
303 bowercopy: {
304 options: {
305 clean: false,
306 report: false,
307 runBower: false,
308 srcPrefix: "bower_components/"
309 },
310 glob: {
311 files: {
312 // When using glob patterns, destinations are *always* folder names
313 // into which matching files will be copied
314 // Also note that subdirectories are **not** maintained
315 // if a destination is specified
316 // For example, one of the files copied here is
317 // 'lodash/dist/lodash.js' -> 'public/js/libs/lodash/lodash.js'
318 '<%= paths.sysext %>core/Resources/Public/Images/colorpicker': 'jquery-minicolors/*.png'
319 }
320 },
321 ckeditor: {
322 options: {
323 destPrefix: "<%= paths.ckeditor %>Public/JavaScript/Contrib"
324 },
325 files: {
326 'ckeditor.js': 'ckeditor/ckeditor.js',
327 'plugins/': 'ckeditor/plugins/',
328 'skins/': 'ckeditor/skins/',
329 'lang/': 'ckeditor/lang/'
330 }
331 },
332 all: {
333 options: {
334 destPrefix: "<%= paths.core %>Public/JavaScript/Contrib"
335 },
336 files: {
337 'nprogress.js': 'nprogress/nprogress.js',
338 'jquery.matchHeight-min.js': 'matchHeight/dist/jquery.matchHeight-min.js',
339 'jquery.dataTables.js': 'datatables/media/js/jquery.dataTables.min.js',
340 'require.js': 'requirejs/require.js',
341 'moment.js': 'moment/min/moment-with-locales.min.js',
342 'moment-timezone.js': 'moment-timezone/builds/moment-timezone-with-data.min.js',
343 'cropper.min.js': 'cropper/dist/cropper.min.js',
344 'imagesloaded.pkgd.min.js': 'imagesloaded/imagesloaded.pkgd.min.js',
345 'bootstrap-datetimepicker.js': 'eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js',
346 'autosize.js': 'autosize/dist/autosize.min.js',
347 'taboverride.min.js': 'taboverride/build/output/taboverride.min.js',
348 'bootstrap-slider.min.js': 'seiyria-bootstrap-slider/dist/bootstrap-slider.min.js',
349 /* disabled until events are not bound to document only
350 see https://github.com/claviska/jquery-minicolors/issues/192
351 see https://github.com/claviska/jquery-minicolors/issues/206
352 'jquery.minicolors.js': 'jquery-minicolors/jquery.minicolors.min.js',
353 */
354 /* disabled until autocomplete formatGroup is fixed to pass on the index too
355 'jquery.autocomplete.js': 'devbridge-autocomplete/src/jquery.autocomplete.js',
356 */
357 'd3/d3.js': 'd3/d3.min.js',
358 /**
359 * copy needed parts of jquery
360 */
361 'jquery/jquery-3.2.1.js': '../node_modules/jquery/dist/jquery.js',
362 'jquery/jquery-3.2.1.min.js': '../node_modules/jquery/dist/jquery.min.js',
363 /**
364 * copy needed parts of jquery-ui
365 */
366 'jquery-ui/core.js': 'jquery-ui/ui/core.js',
367 'jquery-ui/draggable.js': 'jquery-ui/ui/draggable.js',
368 'jquery-ui/droppable.js': 'jquery-ui/ui/droppable.js',
369 'jquery-ui/mouse.js': 'jquery-ui/ui/mouse.js',
370 'jquery-ui/position.js': 'jquery-ui/ui/position.js',
371 'jquery-ui/resizable.js': 'jquery-ui/ui/resizable.js',
372 'jquery-ui/selectable.js': 'jquery-ui/ui/selectable.js',
373 'jquery-ui/sortable.js': 'jquery-ui/ui/sortable.js',
374 'jquery-ui/widget.js': 'jquery-ui/ui/widget.js'
375 }
376 }
377 },
378 uglify: {
379 thirdparty: {
380 files: {
381 "<%= paths.core %>Public/JavaScript/Contrib/require.js": ["<%= paths.core %>Public/JavaScript/Contrib/require.js"],
382 "<%= paths.core %>Public/JavaScript/Contrib/nprogress.js": ["<%= paths.core %>Public/JavaScript/Contrib/nprogress.js"],
383 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/core.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/core.js"],
384 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/draggable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/draggable.js"],
385 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/droppable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/droppable.js"],
386 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/mouse.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/mouse.js"],
387 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/position.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/position.js"],
388 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/resizable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/resizable.js"],
389 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/selectable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/selectable.js"],
390 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/sortable.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/sortable.js"],
391 "<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/widget.js": ["<%= paths.core %>Public/JavaScript/Contrib/jquery-ui/widget.js"],
392 "<%= paths.install %>Public/JavaScript/chosen.jquery.min.js": ["<%= paths.install %>Public/JavaScript/chosen.jquery.js"],
393 "<%= paths.core %>Public/JavaScript/Contrib/bootstrap-datetimepicker.js": ["<%= paths.core %>Public/JavaScript/Contrib/bootstrap-datetimepicker.js"]
394 }
395 }
396 },
397 svgmin: {
398 options: {
399 plugins: [
400 { removeViewBox: false }
401 ]
402 }
403 }
404 });
405
406 // Register tasks
407 grunt.loadNpmTasks('grunt-sass');
408 grunt.loadNpmTasks('grunt-contrib-watch');
409 grunt.loadNpmTasks('grunt-bowercopy');
410 grunt.loadNpmTasks('grunt-npm-install');
411 grunt.loadNpmTasks('grunt-bower-just-install');
412 grunt.loadNpmTasks('grunt-contrib-uglify');
413 grunt.loadNpmTasks('grunt-svgmin');
414 grunt.loadNpmTasks('grunt-postcss');
415 grunt.loadNpmTasks('grunt-contrib-copy');
416 grunt.loadNpmTasks("grunt-ts");
417 grunt.loadNpmTasks('grunt-tslint');
418 grunt.loadNpmTasks('grunt-stylelint');
419
420 /**
421 * grunt default task
422 *
423 * call "$ grunt"
424 *
425 * this will trigger the CSS build
426 */
427 grunt.registerTask('default', ['css']);
428
429 /**
430 * grunt lint
431 *
432 * call "$ grunt lint"
433 *
434 * this task does the following things:
435 * - tslint
436 * - stylelint
437 */
438 grunt.registerTask('lint', ['tslint', 'stylelint']);
439
440 /**
441 * grunt format
442 *
443 * call "$ grunt format"
444 *
445 * this task does the following things:
446 * - formatsass
447 * - lint
448 */
449 grunt.registerTask('format', ['formatsass', 'stylelint']);
450
451 /**
452 * grunt css task
453 *
454 * call "$ grunt css"
455 *
456 * this task does the following things:
457 * - sass
458 * - postcss
459 */
460 grunt.registerTask('css', ['sass', 'postcss']);
461
462 /**
463 * grunt update task
464 *
465 * call "$ grunt update"
466 *
467 * this task does the following things:
468 * - npm install
469 * - bower install
470 * - copy some bower components to a specific destinations because they need to be included via PHP
471 */
472 grunt.registerTask('update', ['npm-install', 'bower_install', 'bowercopy']);
473
474 /**
475 * grunt scripts task
476 *
477 * call "$ grunt scripts"
478 *
479 * this task does the following things:
480 * - 1) Check all TypeScript files (*.ts) with TSLint which are located in sysext/<EXTKEY>/Resources/Private/TypeScript/*.ts
481 * - 2) Compiles all TypeScript files (*.ts) which are located in sysext/<EXTKEY>/Resources/Private/TypeScript/*.ts
482 * - 3) Copy all generated JavaScript and Map files to public folders
483 */
484 grunt.registerTask('scripts', ['tslint', 'tsclean', 'ts', 'copy:ts_files']);
485
486 grunt.task.registerTask('tsclean', function() {
487 grunt.option('force');
488 grunt.file.delete("JavaScript");
489 });
490
491 /**
492 * grunt build task
493 *
494 * call "$ grunt build"
495 *
496 * this task does the following things:
497 * - execute update task
498 * - execute copy task
499 * - compile sass files
500 * - uglify js files
501 * - minifies svg files
502 * - compiles TypeScript files
503 */
504 grunt.registerTask('build', ['update', 'scripts', 'copy', 'format', 'css', 'uglify', 'svgmin']);
505 };