4 const browserSync = require('browser-sync');
5 const csso = require('gulp-csso');
6 const del = require('del');
7 const fs = require('fs');
8 const glob = require('glob');
9 const gap = require('gulp-append-prepend');
10 const replace = require('replace-in-file');
11 const gulp = require('gulp');
12 const argv = require('minimist')(process.argv.slice(2));
13 const gulpif = require('gulp-if');
14 const prefix = require('gulp-autoprefixer');
15 const reload = browserSync.reload;
16 const rename = require('gulp-rename');
17 const sass = require('gulp-sass');
18 const sourcemaps = require('gulp-sourcemaps');
19 const gulp_watch = require('gulp-watch');
22 const packages = require('./package.json');
26 all: [], // must always be empty
28 // Command Line Arguments
31 syncOnly: argv['sync-only'],
35 // Source file locations
38 style_uni: 'interface/themes/style_*.scss',
39 style_color: 'interface/themes/colors/*.scss',
40 directional: 'interface/themes/directional.scss'
44 assets: 'public/assets/'
47 themes: 'public/themes'
51 // Clean up lingering static themes
52 function clean(done) {
53 del.sync([config.dest.themes + "/*"]);
57 // Parses command line arguments
58 function ingest(done) {
59 if (config.dev && typeof config.dev !== "boolean") {
60 // allows for custom proxy to be passed into script
61 config.proxy = config.dev;
67 // definition of header for all compiled css
68 const autoGeneratedHeader = `
69 /*! This style sheet was autogenerated using gulp + scss
70 * For usage instructions, see: https://github.com/openemr/openemr/blob/master/interface/README.md
74 // standard themes css compilation
75 function styles_style_uni() {
76 return gulp.src(config.src.styles.style_uni)
77 .pipe(sourcemaps.init())
78 .pipe(sass().on('error', sass.logError))
79 .pipe(prefix('last 1 version'))
80 .pipe(gap.prependText(autoGeneratedHeader))
81 .pipe(gulpif(!config.dev, csso()))
82 .pipe(gulpif(!config.dev, sourcemaps.write()))
83 .pipe(gulp.dest(config.dest.themes))
84 .pipe(gulpif(config.dev && config.build, gulp.dest(config.dest.themes)))
85 .pipe(gulpif(config.dev, reload({ stream: true })));
88 // color themes css compilation
89 function styles_style_color() {
90 return gulp.src(config.src.styles.style_color)
91 .pipe(sourcemaps.init())
92 .pipe(sass().on('error', sass.logError))
93 .pipe(prefix('last 1 version'))
94 .pipe(gap.prependText(autoGeneratedHeader))
95 .pipe(gulpif(!config.dev, csso()))
96 .pipe(gulpif(!config.dev, sourcemaps.write()))
97 .pipe(gulp.dest(config.dest.themes))
98 .pipe(gulpif(config.dev && config.build, gulp.dest(config.dest.themes)))
99 .pipe(gulpif(config.dev, reload({ stream: true })));
103 const styles = gulp.parallel(styles_style_uni, styles_style_color);
105 // rtl standard themes css compilation
106 function rtl_style_uni() {
107 return gulp.src(config.src.styles.style_uni)
108 .pipe(gap.prependText('@import "./rtl.scss";\n')) // watch out for this relative path!
109 .pipe(sourcemaps.init())
110 .pipe(sass().on('error', sass.logError))
111 .pipe(prefix('last 1 version'))
112 .pipe(gap.prependText(autoGeneratedHeader))
113 .pipe(gulpif(!config.dev, csso()))
114 .pipe(gulpif(!config.dev, sourcemaps.write()))
115 .pipe(rename({ prefix: "rtl_" }))
116 .pipe(gulp.dest(config.dest.themes))
117 .pipe(gulpif(config.dev && config.build, gulp.dest(config.dest.themes)))
118 .pipe(gulpif(config.dev, reload({ stream: true })));
121 // rtl color themes css compilation
122 function rtl_style_color() {
123 return gulp.src(config.src.styles.style_color)
124 .pipe(gap.prependText('@import "../rtl.scss";\n')) // watch out for this relative path!
125 .pipe(sourcemaps.init())
126 .pipe(sass().on('error', sass.logError))
127 .pipe(prefix('last 1 version'))
128 .pipe(gap.prependText(autoGeneratedHeader))
129 .pipe(gulpif(!config.dev, csso()))
130 .pipe(gulpif(!config.dev, sourcemaps.write()))
131 .pipe(rename({ prefix: "rtl_" }))
132 .pipe(gulp.dest(config.dest.themes))
133 .pipe(gulpif(config.dev && config.build, gulp.dest(config.dest.themes)))
134 .pipe(gulpif(config.dev, reload({ stream: true })));
137 // compile rtl themes
138 const rtl_styles = gulp.parallel(rtl_style_uni, rtl_style_color);
140 // append rtl css to all style themes
141 // also, create list of all themes for style_list to use
142 function rtl_setup(done) {
143 const uni = glob.sync(config.src.styles.style_uni);
144 const colors = glob.sync(config.src.styles.style_color);
145 config.all = uni.concat(colors);
147 // backup and update directional file
148 fs.copyFile(config.src.styles.directional, config.src.styles.directional + '.temp', (err) => {
151 files: config.src.styles.directional,
152 from: /ltr \!default/g,
158 function rtl_teardown(done) {
160 files: config.src.styles.directional,
161 from: /rtl \!default/g,
163 }).then(function () {
164 fs.unlink(config.src.styles.directional + '.temp', (err) => {
172 // Copies (and distills, if possible) assets from node_modules to public/assets
173 function install(done) {
174 // combine dependencies and napa sources into one object
175 const dependencies = packages.dependencies;
176 for (let key in packages.napa) {
177 if (packages.napa.hasOwnProperty(key)) {
178 dependencies[key] = packages.napa[key];
182 for (let key in dependencies) {
183 // check if the property/key is defined in the object itself, not in parent
184 if (dependencies.hasOwnProperty(key)) {
186 // dwv is special and need to copy dist, decoders and locales
187 gulp.src('node_modules/' + key + '/dist/**/*')
188 .pipe(gulp.dest(config.dist.assets + key + '/dist'));
189 gulp.src('node_modules/' + key + '/decoders/**/*')
190 .pipe(gulp.dest(config.dist.assets + key + '/decoders'));
191 gulp.src('node_modules/' + key + '/locales/**/*')
192 .pipe(gulp.dest(config.dist.assets + key + '/locales'));
193 } else if (fs.existsSync('node_modules/' + key + '/dist')) {
194 // only copy dist directory, if it exists
195 gulp.src('node_modules/' + key + '/dist/**/*')
196 .pipe(gulp.dest(config.dist.assets + key + '/dist'));
199 gulp.src('node_modules/' + key + '/**/*')
200 .pipe(gulp.dest(config.dist.assets + key));
209 // watch all changes and re-run styles
210 gulp.watch('./interface/**/*.scss', { interval: 1000, mode: 'poll' }, styles);
212 // watch all changes to css/php files in themes and copy to public
213 return gulp_watch('./interface/themes/*.{css,php}', { ignoreInitial: false })
214 .pipe(gulp.dest(config.dest.themes));
217 function sync_only(done) {
219 proxy: "127.0.0.1:" + config.proxy,
225 // Will start browser sync and/or watch changes to scss
226 // = Runs task(styles) first
230 proxy: "127.0.0.1:" + config.proxy
234 // copy all leftover root-level components to the theme directory
235 // hoping this is only temporary
236 return gulp.src(['interface/themes/*.{css,php}'])
237 .pipe(gulp.dest(config.dest.themes));
241 exports.watch = watch;
243 // Export pertinent default task
244 // - Note that the default task runs if no other task is chosen,
245 // which is generally how this script is always used (except in
246 // rare case where the user is running the watch task).
247 if (config.install) {
248 exports.default = gulp.series(install)
249 } else if (config.syncOnly && config.proxy) {
250 exports.default = gulp.parallel(sync_only, watch)
252 exports.default = gulp.series(clean, ingest, styles, sync, rtl_setup, rtl_styles, rtl_teardown);