Build: Make sure `*.cjs` & `*.mjs` files use UNIX line endings as well
[jquery.git] / Gruntfile.js
blob65aec9648a0df07deaab22b377a16baeadacd509
1 "use strict";
3 module.exports = function( grunt ) {
4         function readOptionalJSON( filepath ) {
5                 const stripJSONComments = require( "strip-json-comments" );
6                 let data = {};
7                 try {
8                         data = JSON.parse( stripJSONComments(
9                                 fs.readFileSync( filepath, { encoding: "utf8" } )
10                         ) );
11                 } catch ( e ) {}
12                 return data;
13         }
15         const fs = require( "fs" );
16         const gzip = require( "gzip-js" );
17         const nodeV14OrNewer = !/^v1[0-3]\./.test( process.version );
18         const nodeV17OrNewer = !/^v1[0-6]\./.test( process.version );
19         const customBrowsers = process.env.BROWSERS && process.env.BROWSERS.split( "," );
21         // Support: Node.js <14
22         // Skip running tasks that dropped support for Node.js 10 or 12
23         // in this Node version.
24         function runIfNewNode( task ) {
25                 return nodeV14OrNewer ? task : "print_old_node_message:" + task;
26         }
28         if ( nodeV14OrNewer ) {
29                 const playwright = require( "playwright-webkit" );
30                 process.env.WEBKIT_HEADLESS_BIN = playwright.webkit.executablePath();
31         }
33         if ( !grunt.option( "filename" ) ) {
34                 grunt.option( "filename", "jquery.js" );
35         }
37         grunt.initConfig( {
38                 pkg: grunt.file.readJSON( "package.json" ),
39                 dst: readOptionalJSON( "dist/.destination.json" ),
40                 compare_size: {
41                         files: [ "dist/jquery.js", "dist/jquery.min.js" ],
42                         options: {
43                                 compress: {
44                                         gz: function( contents ) {
45                                                 return gzip.zip( contents, {} ).length;
46                                         }
47                                 },
48                                 cache: "build/.sizecache.json"
49                         }
50                 },
51                 babel: {
52                         options: {
53                                 sourceMap: "inline",
54                                 retainLines: true,
55                                 plugins: [ "@babel/transform-for-of" ]
56                         },
57                         tests: {
58                                 files: {
59                                         "test/data/core/jquery-iterability-transpiled.js":
60                                                 "test/data/core/jquery-iterability-transpiled-es6.js"
61                                 }
62                         }
63                 },
64                 build: {
65                         all: {
66                                 dest: "dist/jquery.js",
67                                 minimum: [
68                                         "core"
69                                 ],
71                                 // Exclude specified modules if the module matching the key is removed
72                                 removeWith: {
73                                         ajax: [ "manipulation/_evalUrl", "deprecated/ajax-event-alias" ],
74                                         callbacks: [ "deferred" ],
75                                         css: [ "effects", "dimensions", "offset" ],
76                                         "css/showHide": [ "effects" ],
77                                         deferred: {
78                                                 remove: [ "ajax", "effects", "queue", "core/ready" ],
79                                                 include: [ "core/ready-no-deferred" ]
80                                         },
81                                         event: [ "deprecated/ajax-event-alias", "deprecated/event" ],
82                                         selector: [ "css/hiddenVisibleSelectors", "effects/animatedSelector" ]
83                                 }
84                         }
85                 },
86                 npmcopy: {
87                         all: {
88                                 options: {
89                                         destPrefix: "external"
90                                 },
91                                 files: {
92                                         "core-js-bundle/core-js-bundle.js": "core-js-bundle/minified.js",
93                                         "core-js-bundle/LICENSE": "core-js-bundle/LICENSE",
95                                         "npo/npo.js": "native-promise-only/lib/npo.src.js",
97                                         "qunit/qunit.js": "qunit/qunit/qunit.js",
98                                         "qunit/qunit.css": "qunit/qunit/qunit.css",
99                                         "qunit/LICENSE.txt": "qunit/LICENSE.txt",
101                                         "requirejs/require.js": "requirejs/require.js",
103                                         "sinon/sinon.js": "sinon/pkg/sinon.js",
104                                         "sinon/LICENSE.txt": "sinon/LICENSE"
105                                 }
106                         }
107                 },
108                 jsonlint: {
109                         pkg: {
110                                 src: [ "package.json" ]
111                         }
112                 },
113                 eslint: {
114                         options: {
115                                 maxWarnings: 0
116                         },
118                         // We have to explicitly declare "src" property otherwise "newer"
119                         // task wouldn't work properly :/
120                         dist: {
121                                 src: [ "dist/jquery.js", "dist/jquery.min.js" ]
122                         },
123                         dev: {
124                                 src: [
125                                         "src/**/*.js",
126                                         "Gruntfile.js",
127                                         "test/**/*.js",
128                                         "build/**/*.js",
130                                         // Ignore files from .eslintignore
131                                         // See https://github.com/sindresorhus/grunt-eslint/issues/119
132                                         ...fs
133                                                 .readFileSync( `${ __dirname }/.eslintignore`, "utf-8" )
134                                                 .split( "\n" )
135                                                 .filter( filePath => filePath )
136                                                 .map( filePath => filePath[ 0 ] === "!" ?
137                                                         filePath.slice( 1 ) :
138                                                         `!${ filePath }`
139                                                 ),
141                                         // Explicitly ignore `dist/` as it could be unignored by
142                                         // the above `.eslintignore` parsing.
143                                         "!dist/**/*.js"
144                                 ]
145                         }
146                 },
147                 testswarm: {
148                         tests: [
150                                 // A special module with basic tests, meant for not fully
151                                 // supported environments like jsdom. We run it everywhere,
152                                 // though, to make sure tests are not broken.
153                                 "basic",
155                                 "ajax",
156                                 "animation",
157                                 "attributes",
158                                 "callbacks",
159                                 "core",
160                                 "css",
161                                 "data",
162                                 "deferred",
163                                 "deprecated",
164                                 "dimensions",
165                                 "effects",
166                                 "event",
167                                 "manipulation",
168                                 "offset",
169                                 "queue",
170                                 "selector",
171                                 "serialize",
172                                 "support",
173                                 "traversing",
174                                 "tween"
175                         ]
176                 },
177                 karma: {
178                         options: {
179                                 customContextFile: "test/karma.context.html",
180                                 customDebugFile: "test/karma.debug.html",
181                                 customLaunchers: {
182                                         ChromeHeadlessNoSandbox: {
183                                                 base: "ChromeHeadless",
184                                                 flags: [ "--no-sandbox" ]
185                                         }
186                                 },
187                                 frameworks: [ "qunit" ],
188                                 middleware: [ "mockserver" ],
189                                 plugins: [
190                                         "karma-*",
191                                         {
192                                                 "middleware:mockserver": [
193                                                         "factory",
194                                                         require( "./test/middleware-mockserver.js" )
195                                                 ]
196                                         }
197                                 ],
198                                 client: {
199                                         qunit: {
201                                                 // We're running `QUnit.start()` ourselves via `loadTests()`
202                                                 // in test/jquery.js
203                                                 autostart: false
204                                         }
205                                 },
206                                 files: [
207                                         "test/data/jquery-1.9.1.js",
208                                         "external/sinon/sinon.js",
209                                         "external/npo/npo.js",
210                                         "external/requirejs/require.js",
211                                         "test/data/testinit.js",
213                                         "test/jquery.js",
215                                         {
216                                                 pattern: "dist/jquery.*",
217                                                 included: false,
218                                                 served: true,
219                                                 nocache: true
220                                         },
221                                         {
222                                                 pattern: "src/**",
223                                                 type: "module",
224                                                 included: false,
225                                                 served: true,
226                                                 nocache: true
227                                         },
228                                         { pattern: "external/**", included: false, served: true },
229                                         {
230                                                 pattern: "test/**/*.@(js|css|jpg|html|xml|svg)",
231                                                 included: false,
232                                                 served: true,
233                                                 nocache: true
234                                         }
235                                 ],
236                                 reporters: [ "dots" ],
237                                 autoWatch: false,
239                                 // 2 minutes; has to be longer than QUnit.config.testTimeout
240                                 browserNoActivityTimeout: 120e3,
242                                 concurrency: 3,
243                                 captureTimeout: 20 * 1000,
244                                 singleRun: true
245                         },
246                         main: {
247                                 browsers: customBrowsers ||
248                                         [ "ChromeHeadless", "FirefoxHeadless", "WebkitHeadless" ]
249                         },
250                         esmodules: {
251                                 browsers: customBrowsers || [ "ChromeHeadless" ],
252                                 options: {
253                                         client: {
254                                                 qunit: {
256                                                         // We're running `QUnit.start()` ourselves via `loadTests()`
257                                                         // in test/jquery.js
258                                                         autostart: false,
260                                                         esmodules: true
261                                                 }
262                                         }
263                                 }
264                         },
266                         jsdom: {
267                                 options: {
268                                         files: [
269                                                 "test/data/jquery-1.9.1.js",
270                                                 "test/data/testinit-jsdom.js",
272                                                 // We don't support various loading methods like esmodules,
273                                                 // choosing a version etc. for jsdom.
274                                                 "dist/jquery.js",
276                                                 // A partial replacement for testinit.js#loadTests()
277                                                 "test/data/testrunner.js",
279                                                 // jsdom only runs basic tests
280                                                 "test/unit/basic.js",
282                                                 {
283                                                         pattern: "test/**/*.@(js|css|jpg|html|xml|svg)",
284                                                         included: false,
285                                                         served: true
286                                                 }
287                                         ]
288                                 },
289                                 browsers: [ "jsdom" ]
290                         },
292                         // To debug tests with Karma:
293                         // 1. Run 'grunt karma:chrome-debug' or 'grunt karma:firefox-debug'
294                         //    (any karma subtask that has singleRun=false)
295                         // 2. Press "Debug" in the opened browser window to start
296                         //    the tests. Unlike the other karma tasks, the debug task will
297                         //    keep the browser window open.
298                         "chrome-debug": {
299                                 browsers: [ "Chrome" ],
300                                 singleRun: false
301                         },
302                         "firefox-debug": {
303                                 browsers: [ "Firefox" ],
304                                 singleRun: false
305                         },
306                         "ie-debug": {
307                                 browsers: [ "IE" ],
308                                 singleRun: false
309                         }
310                 },
311                 watch: {
312                         files: [ "<%= eslint.dev.src %>" ],
313                         tasks: [ "dev" ]
314                 },
315                 terser: {
316                         all: {
317                                 files: {
318                                         "dist/<%= grunt.option('filename').replace('.js', '.min.js') %>":
319                                                 "dist/<%= grunt.option('filename') %>"
320                                 },
321                                 options: {
322                                         ecma: 5,
323                                         sourceMap: {
324                                                 filename: "dist/<%= grunt.option('filename').replace('.js', '.min.map') %>"
325                                         },
326                                         format: {
327                                                 ascii_only: true,
328                                                 comments: false,
329                                                 preamble: "/*! jQuery v<%= pkg.version %> | " +
330                                                         "(c) OpenJS Foundation and other contributors | " +
331                                                         "jquery.org/license */"
332                                         },
333                                         compress: {
334                                                 hoist_funs: false,
335                                                 loops: false
336                                         }
337                                 }
338                         }
339                 }
340         } );
342         // Load grunt tasks from NPM packages
343         require( "load-grunt-tasks" )( grunt, {
344                 pattern: nodeV14OrNewer ? [ "grunt-*" ] : [ "grunt-*", "!grunt-eslint" ]
345         } );
347         // Integrate jQuery specific tasks
348         grunt.loadTasks( "build/tasks" );
350         grunt.registerTask( "print_old_node_message", ( ...args ) => {
351                 var task = args.join( ":" );
352                 grunt.log.writeln( "Old Node.js detected, running the task \"" + task + "\" skipped..." );
353         } );
355         grunt.registerTask( "print_jsdom_message", () => {
356                 grunt.log.writeln( "Node.js 17 or newer detected, skipping jsdom tests..." );
357         } );
359         grunt.registerTask( "lint", [
360                 "jsonlint",
362                 // Running the full eslint task without breaking it down to targets
363                 // would run the dist target first which would point to errors in the built
364                 // file, making it harder to fix them. We want to check the built file only
365                 // if we already know the source files pass the linter.
366                 runIfNewNode( "eslint:dev" ),
367                 runIfNewNode( "eslint:dist" )
368         ] );
370         grunt.registerTask( "lint:newer", [
371                 "newer:jsonlint",
373                 // Don't replace it with just the task; see the above comment.
374                 runIfNewNode( "newer:eslint:dev" ),
375                 runIfNewNode( "newer:eslint:dist" )
376         ] );
378         grunt.registerTask( "test:fast", runIfNewNode( "node_smoke_tests" ) );
379         grunt.registerTask( "test:slow", [
380                 runIfNewNode( "promises_aplus_tests" ),
382                 // Support: Node.js 17+
383                 // jsdom fails to connect to the Karma server in Node 17+.
384                 // Until we figure out a fix, skip jsdom tests there.
385                 nodeV17OrNewer ? "print_jsdom_message" : runIfNewNode( "karma:jsdom" )
386         ] );
388         grunt.registerTask( "test:prepare", [
389                 "npmcopy",
390                 "qunit_fixture",
391                 "babel:tests"
392         ] );
394         grunt.registerTask( "test", [
395                 "test:prepare",
396                 "test:fast",
397                 "test:slow"
398         ] );
400         grunt.registerTask( "dev", [
401                 "build:*:*",
402                 runIfNewNode( "newer:eslint:dev" ),
403                 "newer:terser",
404                 "remove_map_comment",
405                 "dist:*",
406                 "qunit_fixture",
407                 "compare_size"
408         ] );
410         grunt.registerTask( "default", [
411                 runIfNewNode( "eslint:dev" ),
412                 "build:*:*",
413                 "terser",
414                 "remove_map_comment",
415                 "dist:*",
416                 "test:prepare",
417                 runIfNewNode( "eslint:dist" ),
418                 "test:fast",
419                 "compare_size"
420         ] );