diff options
Diffstat (limited to 'present/gulpfile.js')
| -rw-r--r-- | present/gulpfile.js | 319 | 
1 files changed, 319 insertions, 0 deletions
| diff --git a/present/gulpfile.js b/present/gulpfile.js new file mode 100644 index 0000000..6818e8b --- /dev/null +++ b/present/gulpfile.js @@ -0,0 +1,319 @@ +const pkg = require('./package.json') +const path = require('path') +const glob = require('glob') +const yargs = require('yargs') +const colors = require('colors') +const through = require('through2'); +const qunit = require('node-qunit-puppeteer') + +const {rollup} = require('rollup') +const {terser} = require('rollup-plugin-terser') +const babel = require('@rollup/plugin-babel').default +const commonjs = require('@rollup/plugin-commonjs') +const resolve = require('@rollup/plugin-node-resolve').default +const sass = require('sass') + +const gulp = require('gulp') +const tap = require('gulp-tap') +const zip = require('gulp-zip') +const header = require('gulp-header') +const eslint = require('gulp-eslint') +const minify = require('gulp-clean-css') +const connect = require('gulp-connect') +const autoprefixer = require('gulp-autoprefixer') + +const root = yargs.argv.root || '.' +const port = yargs.argv.port || 8000 +const host = yargs.argv.host || 'localhost' + +const banner = `/*! +* reveal.js ${pkg.version} +* ${pkg.homepage} +* MIT licensed +* +* Copyright (C) 2011-2023 Hakim El Hattab, https://hakim.se +*/\n` + +// Prevents warnings from opening too many test pages +process.setMaxListeners(20); + +const babelConfig = { +    babelHelpers: 'bundled', +    ignore: ['node_modules'], +    compact: false, +    extensions: ['.js', '.html'], +    plugins: [ +        'transform-html-import-to-string' +    ], +    presets: [[ +        '@babel/preset-env', +        { +            corejs: 3, +            useBuiltIns: 'usage', +            modules: false +        } +    ]] +}; + +// Our ES module bundle only targets newer browsers with +// module support. Browsers are targeted explicitly instead +// of using the "esmodule: true" target since that leads to +// polyfilling older browsers and a larger bundle. +const babelConfigESM = JSON.parse( JSON.stringify( babelConfig ) ); +babelConfigESM.presets[0][1].targets = { browsers: [ +    'last 2 Chrome versions', +    'last 2 Safari versions', +    'last 2 iOS versions', +    'last 2 Firefox versions', +    'last 2 Edge versions', +] }; + +let cache = {}; + +// Creates a bundle with broad browser support, exposed +// as UMD +gulp.task('js-es5', () => { +    return rollup({ +        cache: cache.umd, +        input: 'js/index.js', +        plugins: [ +            resolve(), +            commonjs(), +            babel( babelConfig ), +            terser() +        ] +    }).then( bundle => { +        cache.umd = bundle.cache; +        return bundle.write({ +            name: 'Reveal', +            file: './dist/reveal.js', +            format: 'umd', +            banner: banner, +            sourcemap: true +        }); +    }); +}) + +// Creates an ES module bundle +gulp.task('js-es6', () => { +    return rollup({ +        cache: cache.esm, +        input: 'js/index.js', +        plugins: [ +            resolve(), +            commonjs(), +            babel( babelConfigESM ), +            terser() +        ] +    }).then( bundle => { +        cache.esm = bundle.cache; +        return bundle.write({ +            file: './dist/reveal.esm.js', +            format: 'es', +            banner: banner, +            sourcemap: true +        }); +    }); +}) +gulp.task('js', gulp.parallel('js-es5', 'js-es6')); + +// Creates a UMD and ES module bundle for each of our +// built-in plugins +gulp.task('plugins', () => { +    return Promise.all([ +        { name: 'RevealHighlight', input: './plugin/highlight/plugin.js', output: './plugin/highlight/highlight' }, +        { name: 'RevealMarkdown', input: './plugin/markdown/plugin.js', output: './plugin/markdown/markdown' }, +        { name: 'RevealSearch', input: './plugin/search/plugin.js', output: './plugin/search/search' }, +        { name: 'RevealNotes', input: './plugin/notes/plugin.js', output: './plugin/notes/notes' }, +        { name: 'RevealZoom', input: './plugin/zoom/plugin.js', output: './plugin/zoom/zoom' }, +        { name: 'RevealMath', input: './plugin/math/plugin.js', output: './plugin/math/math' }, +    ].map( plugin => { +        return rollup({ +                cache: cache[plugin.input], +                input: plugin.input, +                plugins: [ +                    resolve(), +                    commonjs(), +                    babel({ +                        ...babelConfig, +                        ignore: [/node_modules\/(?!(highlight\.js|marked)\/).*/], +                    }), +                    terser() +                ] +            }).then( bundle => { +                cache[plugin.input] = bundle.cache; +                bundle.write({ +                    file: plugin.output + '.esm.js', +                    name: plugin.name, +                    format: 'es' +                }) + +                bundle.write({ +                    file: plugin.output + '.js', +                    name: plugin.name, +                    format: 'umd' +                }) +            }); +    } )); +}) + +// a custom pipeable step to transform Sass to CSS +function compileSass() { +  return through.obj( ( vinylFile, encoding, callback ) => { +    const transformedFile = vinylFile.clone(); + +    sass.render({ +        data: transformedFile.contents.toString(), +        includePaths: ['css/', 'css/theme/template'] +    }, ( err, result ) => { +        if( err ) { +            console.log( vinylFile.path ); +            console.log( err.formatted ); +        } +        else { +            transformedFile.extname = '.css'; +            transformedFile.contents = result.css; +            callback( null, transformedFile ); +        } +    }); +  }); +} + +gulp.task('css-themes', () => gulp.src(['./css/theme/source/*.{sass,scss}']) +        .pipe(compileSass()) +        .pipe(gulp.dest('./dist/theme'))) + +gulp.task('css-core', () => gulp.src(['css/reveal.scss']) +    .pipe(compileSass()) +    .pipe(autoprefixer()) +    .pipe(minify({compatibility: 'ie9'})) +    .pipe(header(banner)) +    .pipe(gulp.dest('./dist'))) + +gulp.task('css', gulp.parallel('css-themes', 'css-core')) + +gulp.task('qunit', () => { + +    let serverConfig = { +        root, +        port: 8009, +        host: 'localhost', +        name: 'test-server' +    } + +    let server = connect.server( serverConfig ) + +    let testFiles = glob.sync('test/*.html' ) + +    let totalTests = 0; +    let failingTests = 0; + +    let tests = Promise.all( testFiles.map( filename => { +        return new Promise( ( resolve, reject ) => { +            qunit.runQunitPuppeteer({ +                targetUrl: `http://${serverConfig.host}:${serverConfig.port}/${filename}`, +                timeout: 20000, +                redirectConsole: false, +                puppeteerArgs: ['--allow-file-access-from-files'] +            }) +                .then(result => { +                    if( result.stats.failed > 0 ) { +                        console.log(`${'!'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.red); +                        // qunit.printResultSummary(result, console); +                        qunit.printFailedTests(result, console); +                    } +                    else { +                        console.log(`${'✔'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.green); +                    } + +                    totalTests += result.stats.total; +                    failingTests += result.stats.failed; + +                    resolve(); +                }) +                .catch(error => { +                    console.error(error); +                    reject(); +                }); +        } ) +    } ) ); + +    return new Promise( ( resolve, reject ) => { + +        tests.then( () => { +                if( failingTests > 0 ) { +                    reject( new Error(`${failingTests}/${totalTests} tests failed`.red) ); +                } +                else { +                    console.log(`${'✔'} Passed ${totalTests} tests`.green.bold); +                    resolve(); +                } +            } ) +            .catch( () => { +                reject(); +            } ) +            .finally( () => { +                server.close(); +            } ); + +    } ); +} ) + +gulp.task('eslint', () => gulp.src(['./js/**', 'gulpfile.js']) +        .pipe(eslint()) +        .pipe(eslint.format())) + +gulp.task('test', gulp.series( 'eslint', 'qunit' )) + +gulp.task('default', gulp.series(gulp.parallel('js', 'css', 'plugins'), 'test')) + +gulp.task('build', gulp.parallel('js', 'css', 'plugins')) + +gulp.task('package', gulp.series(() => + +    gulp.src( +        [ +            './index.html', +            './dist/**', +            './lib/**', +            './images/**', +            './plugin/**', +            './**/*.md' +        ], +        { base: './' } +    ) +    .pipe(zip('reveal-js-presentation.zip')).pipe(gulp.dest('./')) + +)) + +gulp.task('reload', () => gulp.src(['**/*.html', '**/*.md']) +    .pipe(connect.reload())); + +gulp.task('serve', () => { + +    connect.server({ +        root: root, +        port: port, +        host: host, +        livereload: true +    }) + +    gulp.watch(['**/*.html', '**/*.md'], gulp.series('reload')) + +    gulp.watch(['js/**'], gulp.series('js', 'reload', 'eslint')) + +    gulp.watch(['plugin/**/plugin.js', 'plugin/**/*.html'], gulp.series('plugins', 'reload')) + +    gulp.watch([ +        'css/theme/source/*.{sass,scss}', +        'css/theme/template/*.{sass,scss}', +    ], gulp.series('css-themes', 'reload')) + +    gulp.watch([ +        'css/*.scss', +        'css/print/*.{sass,scss,css}' +    ], gulp.series('css-core', 'reload')) + +    gulp.watch(['test/*.html'], gulp.series('test')) + +}) | 
