Christophe Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 1 | const pkg = require('./package.json') |
| 2 | const path = require('path') |
| 3 | const glob = require('glob') |
| 4 | const yargs = require('yargs') |
| 5 | const colors = require('colors') |
| 6 | const through = require('through2'); |
| 7 | const qunit = require('node-qunit-puppeteer') |
| 8 | |
| 9 | const {rollup} = require('rollup') |
| 10 | const {terser} = require('rollup-plugin-terser') |
| 11 | const babel = require('@rollup/plugin-babel').default |
| 12 | const commonjs = require('@rollup/plugin-commonjs') |
| 13 | const resolve = require('@rollup/plugin-node-resolve').default |
| 14 | const sass = require('sass') |
| 15 | |
| 16 | const gulp = require('gulp') |
| 17 | const tap = require('gulp-tap') |
| 18 | const zip = require('gulp-zip') |
| 19 | const header = require('gulp-header') |
| 20 | const eslint = require('gulp-eslint') |
| 21 | const minify = require('gulp-clean-css') |
| 22 | const connect = require('gulp-connect') |
| 23 | const autoprefixer = require('gulp-autoprefixer') |
| 24 | |
| 25 | const root = yargs.argv.root || '.' |
| 26 | const port = yargs.argv.port || 8000 |
Christophe Dervieux | 8afae13 | 2021-12-06 15:16:42 +0100 | [diff] [blame] | 27 | const host = yargs.argv.host || 'localhost' |
Christophe Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 28 | |
| 29 | const banner = `/*! |
| 30 | * reveal.js ${pkg.version} |
| 31 | * ${pkg.homepage} |
| 32 | * MIT licensed |
| 33 | * |
Christophe Dervieux | 8afae13 | 2021-12-06 15:16:42 +0100 | [diff] [blame] | 34 | * Copyright (C) 2011-2021 Hakim El Hattab, https://hakim.se |
Christophe Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 35 | */\n` |
| 36 | |
| 37 | // Prevents warnings from opening too many test pages |
| 38 | process.setMaxListeners(20); |
| 39 | |
| 40 | const 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. |
| 62 | const babelConfigESM = JSON.parse( JSON.stringify( babelConfig ) ); |
| 63 | babelConfigESM.presets[0][1].targets = { browsers: [ |
Christophe Dervieux | 8afae13 | 2021-12-06 15:16:42 +0100 | [diff] [blame] | 64 | '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 Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 69 | ] }; |
| 70 | |
| 71 | let cache = {}; |
| 72 | |
| 73 | // Creates a bundle with broad browser support, exposed |
| 74 | // as UMD |
| 75 | gulp.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 |
| 98 | gulp.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 | }) |
| 118 | gulp.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 |
| 122 | gulp.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 |
| 161 | function 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 | |
| 182 | gulp.task('css-themes', () => gulp.src(['./css/theme/source/*.{sass,scss}']) |
| 183 | .pipe(compileSass()) |
| 184 | .pipe(gulp.dest('./dist/theme'))) |
| 185 | |
| 186 | gulp.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 | |
| 193 | gulp.task('css', gulp.parallel('css-themes', 'css-core')) |
| 194 | |
| 195 | gulp.task('qunit', () => { |
| 196 | |
| 197 | let serverConfig = { |
| 198 | root, |
| 199 | port: 8009, |
Christophe Dervieux | 8afae13 | 2021-12-06 15:16:42 +0100 | [diff] [blame] | 200 | host: 'localhost', |
Christophe Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 201 | 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 | |
| 262 | gulp.task('eslint', () => gulp.src(['./js/**', 'gulpfile.js']) |
| 263 | .pipe(eslint()) |
| 264 | .pipe(eslint.format())) |
| 265 | |
| 266 | gulp.task('test', gulp.series( 'eslint', 'qunit' )) |
| 267 | |
| 268 | gulp.task('default', gulp.series(gulp.parallel('js', 'css', 'plugins'), 'test')) |
| 269 | |
| 270 | gulp.task('build', gulp.parallel('js', 'css', 'plugins')) |
| 271 | |
| 272 | gulp.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 | |
| 285 | gulp.task('reload', () => gulp.src(['*.html', '*.md']) |
| 286 | .pipe(connect.reload())); |
| 287 | |
| 288 | gulp.task('serve', () => { |
| 289 | |
| 290 | connect.server({ |
| 291 | root: root, |
| 292 | port: port, |
Christophe Dervieux | 8afae13 | 2021-12-06 15:16:42 +0100 | [diff] [blame] | 293 | host: host, |
Christophe Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 294 | livereload: true |
| 295 | }) |
| 296 | |
| 297 | gulp.watch(['*.html', '*.md'], gulp.series('reload')) |
| 298 | |
Christophe Dervieux | 8afae13 | 2021-12-06 15:16:42 +0100 | [diff] [blame] | 299 | gulp.watch(['js/**'], gulp.series('js', 'reload', 'eslint')) |
Christophe Dervieux | e1893ae | 2021-10-07 17:09:02 +0200 | [diff] [blame] | 300 | |
| 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 | }) |