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