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