blob: 23a25a87a779e0370bb74bf00178a1e5294518bb [file] [log] [blame]
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +02001const pkg = require('./package.json')
2const path = require('path')
3const glob = require('glob')
4const yargs = require('yargs')
5const colors = require('colors')
6const through = require('through2');
7const qunit = require('node-qunit-puppeteer')
8
9const {rollup} = require('rollup')
10const {terser} = require('rollup-plugin-terser')
11const babel = require('@rollup/plugin-babel').default
12const commonjs = require('@rollup/plugin-commonjs')
13const resolve = require('@rollup/plugin-node-resolve').default
14const sass = require('sass')
15
16const gulp = require('gulp')
17const tap = require('gulp-tap')
18const zip = require('gulp-zip')
19const header = require('gulp-header')
20const eslint = require('gulp-eslint')
21const minify = require('gulp-clean-css')
22const connect = require('gulp-connect')
23const autoprefixer = require('gulp-autoprefixer')
24
25const root = yargs.argv.root || '.'
26const port = yargs.argv.port || 8000
Christophe Dervieux8afae132021-12-06 15:16:42 +010027const host = yargs.argv.host || 'localhost'
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +020028
29const banner = `/*!
30* reveal.js ${pkg.version}
31* ${pkg.homepage}
32* MIT licensed
33*
Christophe Dervieux8afae132021-12-06 15:16:42 +010034* Copyright (C) 2011-2021 Hakim El Hattab, https://hakim.se
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +020035*/\n`
36
37// Prevents warnings from opening too many test pages
38process.setMaxListeners(20);
39
40const babelConfig = {
41 babelHelpers: 'bundled',
42 ignore: ['node_modules'],
43 compact: false,
44 extensions: ['.js', '.html'],
45 plugins: [
46 'transform-html-import-to-string'
47 ],
48 presets: [[
49 '@babel/preset-env',
50 {
51 corejs: 3,
52 useBuiltIns: 'usage',
53 modules: false
54 }
55 ]]
56};
57
58// Our ES module bundle only targets newer browsers with
59// module support. Browsers are targeted explicitly instead
60// of using the "esmodule: true" target since that leads to
61// polyfilling older browsers and a larger bundle.
62const babelConfigESM = JSON.parse( JSON.stringify( babelConfig ) );
63babelConfigESM.presets[0][1].targets = { browsers: [
Christophe Dervieux8afae132021-12-06 15:16:42 +010064 'last 2 Chrome versions',
65 'last 2 Safari versions',
66 'last 2 iOS versions',
67 'last 2 Firefox versions',
68 'last 2 Edge versions',
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +020069] };
70
71let cache = {};
72
73// Creates a bundle with broad browser support, exposed
74// as UMD
75gulp.task('js-es5', () => {
76 return rollup({
77 cache: cache.umd,
78 input: 'js/index.js',
79 plugins: [
80 resolve(),
81 commonjs(),
82 babel( babelConfig ),
83 terser()
84 ]
85 }).then( bundle => {
86 cache.umd = bundle.cache;
87 return bundle.write({
88 name: 'Reveal',
89 file: './dist/reveal.js',
90 format: 'umd',
91 banner: banner,
92 sourcemap: true
93 });
94 });
95})
96
97// Creates an ES module bundle
98gulp.task('js-es6', () => {
99 return rollup({
100 cache: cache.esm,
101 input: 'js/index.js',
102 plugins: [
103 resolve(),
104 commonjs(),
105 babel( babelConfigESM ),
106 terser()
107 ]
108 }).then( bundle => {
109 cache.esm = bundle.cache;
110 return bundle.write({
111 file: './dist/reveal.esm.js',
112 format: 'es',
113 banner: banner,
114 sourcemap: true
115 });
116 });
117})
118gulp.task('js', gulp.parallel('js-es5', 'js-es6'));
119
120// Creates a UMD and ES module bundle for each of our
121// built-in plugins
122gulp.task('plugins', () => {
123 return Promise.all([
124 { name: 'RevealHighlight', input: './plugin/highlight/plugin.js', output: './plugin/highlight/highlight' },
125 { name: 'RevealMarkdown', input: './plugin/markdown/plugin.js', output: './plugin/markdown/markdown' },
126 { name: 'RevealSearch', input: './plugin/search/plugin.js', output: './plugin/search/search' },
127 { name: 'RevealNotes', input: './plugin/notes/plugin.js', output: './plugin/notes/notes' },
128 { name: 'RevealZoom', input: './plugin/zoom/plugin.js', output: './plugin/zoom/zoom' },
129 { name: 'RevealMath', input: './plugin/math/plugin.js', output: './plugin/math/math' },
130 ].map( plugin => {
131 return rollup({
132 cache: cache[plugin.input],
133 input: plugin.input,
134 plugins: [
135 resolve(),
136 commonjs(),
137 babel({
138 ...babelConfig,
139 ignore: [/node_modules\/(?!(highlight\.js|marked)\/).*/],
140 }),
141 terser()
142 ]
143 }).then( bundle => {
144 cache[plugin.input] = bundle.cache;
145 bundle.write({
146 file: plugin.output + '.esm.js',
147 name: plugin.name,
148 format: 'es'
149 })
150
151 bundle.write({
152 file: plugin.output + '.js',
153 name: plugin.name,
154 format: 'umd'
155 })
156 });
157 } ));
158})
159
160// a custom pipeable step to transform Sass to CSS
161function compileSass() {
162 return through.obj( ( vinylFile, encoding, callback ) => {
163 const transformedFile = vinylFile.clone();
164
165 sass.render({
166 data: transformedFile.contents.toString(),
167 includePaths: ['css/', 'css/theme/template']
168 }, ( err, result ) => {
169 if( err ) {
170 console.log( vinylFile.path );
171 console.log( err.formatted );
172 }
173 else {
174 transformedFile.extname = '.css';
175 transformedFile.contents = result.css;
176 callback( null, transformedFile );
177 }
178 });
179 });
180}
181
182gulp.task('css-themes', () => gulp.src(['./css/theme/source/*.{sass,scss}'])
183 .pipe(compileSass())
184 .pipe(gulp.dest('./dist/theme')))
185
186gulp.task('css-core', () => gulp.src(['css/reveal.scss'])
187 .pipe(compileSass())
188 .pipe(autoprefixer())
189 .pipe(minify({compatibility: 'ie9'}))
190 .pipe(header(banner))
191 .pipe(gulp.dest('./dist')))
192
193gulp.task('css', gulp.parallel('css-themes', 'css-core'))
194
195gulp.task('qunit', () => {
196
197 let serverConfig = {
198 root,
199 port: 8009,
Christophe Dervieux8afae132021-12-06 15:16:42 +0100200 host: 'localhost',
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +0200201 name: 'test-server'
202 }
203
204 let server = connect.server( serverConfig )
205
206 let testFiles = glob.sync('test/*.html' )
207
208 let totalTests = 0;
209 let failingTests = 0;
210
211 let tests = Promise.all( testFiles.map( filename => {
212 return new Promise( ( resolve, reject ) => {
213 qunit.runQunitPuppeteer({
214 targetUrl: `http://${serverConfig.host}:${serverConfig.port}/${filename}`,
215 timeout: 20000,
216 redirectConsole: false,
217 puppeteerArgs: ['--allow-file-access-from-files']
218 })
219 .then(result => {
220 if( result.stats.failed > 0 ) {
221 console.log(`${'!'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.red);
222 // qunit.printResultSummary(result, console);
223 qunit.printFailedTests(result, console);
224 }
225 else {
226 console.log(`${'✔'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.green);
227 }
228
229 totalTests += result.stats.total;
230 failingTests += result.stats.failed;
231
232 resolve();
233 })
234 .catch(error => {
235 console.error(error);
236 reject();
237 });
238 } )
239 } ) );
240
241 return new Promise( ( resolve, reject ) => {
242
243 tests.then( () => {
244 if( failingTests > 0 ) {
245 reject( new Error(`${failingTests}/${totalTests} tests failed`.red) );
246 }
247 else {
248 console.log(`${'✔'} Passed ${totalTests} tests`.green.bold);
249 resolve();
250 }
251 } )
252 .catch( () => {
253 reject();
254 } )
255 .finally( () => {
256 server.close();
257 } );
258
259 } );
260} )
261
262gulp.task('eslint', () => gulp.src(['./js/**', 'gulpfile.js'])
263 .pipe(eslint())
264 .pipe(eslint.format()))
265
266gulp.task('test', gulp.series( 'eslint', 'qunit' ))
267
268gulp.task('default', gulp.series(gulp.parallel('js', 'css', 'plugins'), 'test'))
269
270gulp.task('build', gulp.parallel('js', 'css', 'plugins'))
271
272gulp.task('package', gulp.series('default', () =>
273
274 gulp.src([
275 './index.html',
276 './dist/**',
277 './lib/**',
278 './images/**',
279 './plugin/**',
280 './**.md'
281 ]).pipe(zip('reveal-js-presentation.zip')).pipe(gulp.dest('./'))
282
283))
284
285gulp.task('reload', () => gulp.src(['*.html', '*.md'])
286 .pipe(connect.reload()));
287
288gulp.task('serve', () => {
289
290 connect.server({
291 root: root,
292 port: port,
Christophe Dervieux8afae132021-12-06 15:16:42 +0100293 host: host,
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +0200294 livereload: true
295 })
296
297 gulp.watch(['*.html', '*.md'], gulp.series('reload'))
298
Christophe Dervieux8afae132021-12-06 15:16:42 +0100299 gulp.watch(['js/**'], gulp.series('js', 'reload', 'eslint'))
Christophe Dervieuxe1893ae2021-10-07 17:09:02 +0200300
301 gulp.watch(['plugin/**/plugin.js'], gulp.series('plugins', 'reload'))
302
303 gulp.watch([
304 'css/theme/source/*.{sass,scss}',
305 'css/theme/template/*.{sass,scss}',
306 ], gulp.series('css-themes', 'reload'))
307
308 gulp.watch([
309 'css/*.scss',
310 'css/print/*.{sass,scss,css}'
311 ], gulp.series('css-core', 'reload'))
312
313 gulp.watch(['test/*.html'], gulp.series('test'))
314
315})