'use strict'; import cloneDeep from 'lodash.clonedeep'; import { series, parallel, dest, src, watch, task } from 'gulp'; import rollup from '@rollup/stream'; import sourcemaps from 'gulp-sourcemaps'; import source from 'vinyl-source-stream'; import buffer from 'vinyl-buffer'; import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; import eslint from '@rollup/plugin-eslint'; import rollupCss from 'rollup-plugin-css-porter'; import gulpif from 'gulp-if'; import uglify from 'gulp-uglify'; import gulpsass from 'gulp-dart-sass'; // TODO: move to gulp-sass once they removed the node-sass depenency import postcss from 'gulp-postcss'; import zip from 'gulp-zip'; import glob from 'glob'; import path from 'path'; import subprocess from 'child_process'; import fs from 'fs'; // css post-processing import cssnano from 'cssnano'; import autoprefixer from 'autoprefixer'; import concatCss from 'gulp-concat-css'; var minify = false; var postcss_plugins = [ // always add autoprefixer autoprefixer(), ]; /* eslint Configuration */ var eslint_config = { "envs": ["es6"], "globals": [ "window", "console", "document", "setInterval", "clearInterval", "setTimeout", "clearTimeout", "XMLHttpRequest", "btoa", "atob", "Audio", "MutationObserver", "URLSearchParams", // form vendor.js: "NoSleep", "$", "moment", "toastr", "bootbox", "Popper", ], "parserOptions": { "sourceType": "module", "ecmaVersion": 2018 }, baseConfig: { "extends": ["eslint:recommended"] }, rules: { "no-unused-vars": ["error", { vars: "all", args: "none" }] } }; var view_eslint_config = cloneDeep(eslint_config); view_eslint_config.globals = eslint_config.globals.concat([ "Grocy", "__t", "GrocyClass", "__n", "U", "RefreshContextualTimeago", "RefreshLocaleNumberDisplay", "RefreshLocaleNumberInput", "LoadImagesLazy", "EmptyElementWhenMatches", "animateCSS" ]); // viewjs handling var files = glob.sync('./js/viewjs/*.js'); var viewJStasks = []; files.forEach(function(target) { task(target, cb => rollup({ input: target, output: { format: 'umd', name: path.basename(target), sourcemap: 'inline', }, plugins: [resolve(), rollupCss({ dest: path.resolve('./public/css/viewcss/' + path.basename(target).replace(".js", ".css")), }), commonjs(), eslint(view_eslint_config)], }) .pipe(source(path.basename(target), "./js/viewjs")) .pipe(buffer()) .pipe(gulpif(minify, uglify())) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) .pipe(sourcemaps.write('.', { sourceMappingURLPrefix: '/viewjs' })) .pipe(dest('./public/viewjs'))); viewJStasks.push(target); }); // The `clean` function is not exported so it can be considered a private task. // It can still be used within the `series()` composition. function clean(cb) { // body omitted cb(); } // The `build` function is exported so it is public and can be run with the `gulp` command. // It can also be used within the `series()` composition. function build(cb) { // body omitted return parallel( js, css, vendor, viewjs, resourceFileCopy, copyLocales, makeLocales)(cb); } function publish(cb) { minify = true; postcss_plugins.push(cssnano()) return build(cb); } function js(cb) { return rollup({ input: './js/grocy.js', output: { format: 'umd', name: 'grocy.js', sourcemap: 'inline', }, plugins: [resolve(), commonjs(), eslint(eslint_config)], }) .pipe(source('grocy.js', "./js")) .pipe(buffer()) .pipe(gulpif(minify, uglify())) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) .pipe(sourcemaps.write('.')) .pipe(dest('./public/js')); } function viewjs(cb) { return parallel(viewJStasks)(cb); } function vendor(cb) { return rollup({ input: './js/vendor.js', output: { format: 'umd', name: 'grocy.js', sourcemap: 'inline', }, plugins: [resolve(), commonjs()], }) .pipe(source('vendor.js', "./js")) .pipe(buffer()) .pipe(gulpif(minify, uglify())) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) .pipe(sourcemaps.write('.')) .pipe(dest('./public/js')); } function css(cb) { return src('./scss/grocy.scss') .pipe(sourcemaps.init()) .pipe(gulpsass({ includePaths: ['./node_modules'], quietDeps: true }).on('error', gulpsass.logError)) .pipe(concatCss('grocy.css', { includePaths: ['./node_modules'], rebaseUrls: false })) .pipe(postcss(postcss_plugins)) .pipe(sourcemaps.write('.')) .pipe(dest('./public/css')) } function resourceFileCopy(cb) { return parallel( cb => src([ './node_modules/@fortawesome/fontawesome-free/webfonts/*' ]).pipe(dest('./public/webfonts')), cb => src('./node_modules/summernote/dist/font/*').pipe(dest('./public/css/font')), )(cb); } async function makeLocales() { return subprocess.exec("php buildfiles/generate-locales.php"); } function copyLocales(cb) { return parallel( cb => src('./node_modules/timeago/locales/*.js').pipe(dest('./public/js/locales/timeago')), cb => src('./node_modules/summernote/dist/lang/*.js').pipe(dest('./public/js/locales/summernote')), cb => src('./node_modules/bootstrap-select/dist/js/i18n/*').pipe(dest('./public/js/locales/bootstrap-select')), cb => src('./node_modules/fullcalendar/dist/locale/*').pipe(dest('./public/js/locales/fullcalendar')), cb => src('./node_modules/@fullcalendar/core/locales/*').pipe(dest('./public/js/locales/fullcalendar-core')), )(cb); } function live(cb) { watch('./scss/**/*.scss', css); watch(['./js/**/*.js', '!./js/viewjs/**/*.js'], js); watch('./js/vendor.js', vendor); //watch('./js/viewjs/**/*.js', viewjs); viewJStasks.forEach(elem => watch(elem, series([elem]))); } function release(cb) { return series(publish, bundle)(cb); } function bundle(cb) { var version = subprocess.spawnSync('git', ['describe', '--tags'], { cwd: process.cwd(), stdio: 'pipe', }); var today = new Date(); var versionObject = { Version: version.output[1].toString().substring(1).replace('\n', ''), ReleaseDate: today.getFullYear().toString() + "-" + today.getMonth().toString().padStart(2, "0") + "-" + today.getDay().toString().padStart(2, "0"), }; fs.writeFileSync("version.json", JSON.stringify(versionObject, null, 2)); return src([ '**/*', '!./.*', '!.git/**/*', '!.yarn/**/*', '!.devtools/**/*', '!.github/**/*', '!.tx/**/*', '!.release/**/*', '!public/.gitignore', '!data/plugins/.gitignore', '!data/.gitignore', '!yarn.lock', '!package.json', '!postcss.config.js', '!gulpfile.babel.js', '!composer.json', '!composer.lock', '!node_modules/**', '!js/**/*', '!scss/**/*', '!data/config.php', '!data/storage/**/*', '!data/grocy.db', ], { dot: true }).pipe(zip('grocy-' + versionObject.Version + '.zip')) .pipe(dest('.release')) } export default publish; export { build, js, vendor, viewjs, css, live, clean, resourceFileCopy, copyLocales, publish, release, bundle, makeLocales }