First impression, update the look of the landing page (#3626)
[openemr.git] / gulpfile.js
blob29cd707d8aaa565eb5ee880fa6c008ff0f3afe78
1 'use strict';
3 // modules
4 const csso = require('gulp-csso');
5 const del = require('del');
6 const fs = require('fs');
7 const glob = require('glob');
8 const gap = require('gulp-append-prepend');
9 const replace = require('replace-in-file');
10 const gulp = require('gulp');
11 const argv = require('minimist')(process.argv.slice(2));
12 const gulpif = require('gulp-if');
13 const prefix = require('autoprefixer');
14 const postcss = require('gulp-postcss');
15 const rename = require('gulp-rename');
16 const sass = require('gulp-sass');
17 const sourcemaps = require('gulp-sourcemaps');
18 const gulp_watch = require('gulp-watch');
19 const injector = require('gulp-inject-string');
21 // package.json
22 const packages = require('./package.json');
24 // configuration
25 let config = {
26     all: [], // must always be empty
28     // Command Line Arguments
29     dev: argv['dev'],
30     build: argv['b'],
31     install: argv['i'],
33     // Source file locations
34     src: {
35         styles: {
36             style_portal: 'interface/themes/patientportal-*.scss',
37             style_tabs: 'interface/themes/tabs_style_*.scss',
38             style_uni: 'interface/themes/oe-styles/style_*.scss',
39             style_color: 'interface/themes/colors/*.scss',
40             directional: 'interface/themes/directional.scss'
41         }
42     },
43     dist: {
44         assets: 'public/assets/'
45     },
46     dest: {
47         themes: 'public/themes'
48     }
51 // Clean up lingering static themes
52 function clean(done) {
53     del.sync([config.dest.themes + "/*"]);
54     done();
57 // Parses command line arguments
58 function ingest(done) {
59     if (config.dev && typeof config.dev !== "boolean") {
60         config.dev = true;
61     }
62     done();
65 // definition of header for all compiled css
66 const autoGeneratedHeader = `
67 /*! This style sheet was autogenerated using gulp + scss
68  *  For usage instructions, see: https://github.com/openemr/openemr/blob/master/interface/README.md
69  */
72 // standard themes css compilation
73 function styles_style_portal() {
74     return gulp.src(config.src.styles.style_portal)
75     .pipe(injector.replace('// bs4import', '@import "../../public/assets/bootstrap/scss/bootstrap";'))
76     .pipe(sourcemaps.init())
77     .pipe(sass().on('error', sass.logError))
78     .pipe(postcss([ prefix() ]))
79     .pipe(gap.prependText(autoGeneratedHeader))
80     .pipe(gulpif(!config.dev, csso()))
81     .pipe(gulpif(!config.dev, sourcemaps.write()))
82     .pipe(gulp.dest(config.dest.themes));
84 // standard themes css compilation
85 function styles_style_uni() {
86     return gulp.src(config.src.styles.style_uni)
87         .pipe(injector.replace('// bs4import', '@import "../../../public/assets/bootstrap/scss/bootstrap";'))
88         .pipe(sourcemaps.init())
89         .pipe(sass().on('error', sass.logError))
90         .pipe(postcss([ prefix() ]))
91         .pipe(gap.prependText(autoGeneratedHeader))
92         .pipe(gulpif(!config.dev, csso()))
93         .pipe(gulpif(!config.dev, sourcemaps.write()))
94         .pipe(gulp.dest(config.dest.themes));
97 // color themes css compilation
98 function styles_style_color() {
99     return gulp.src(config.src.styles.style_color)
100         .pipe(injector.replace('// bs4import', '@import "../../../public/assets/bootstrap/scss/bootstrap";'))
101         .pipe(sourcemaps.init())
102         .pipe(sass().on('error', sass.logError))
103         .pipe(postcss([ prefix() ]))
104         .pipe(gap.prependText(autoGeneratedHeader))
105         .pipe(gulpif(!config.dev, csso()))
106         .pipe(gulpif(!config.dev, sourcemaps.write()))
107         .pipe(gulp.dest(config.dest.themes));
110 // Tabs CSS compilation
111 function styles_style_tabs() {
112     return gulp.src(config.src.styles.style_tabs)
113         .pipe(sourcemaps.init())
114         .pipe(sass().on('error', sass.logError))
115         .pipe(postcss([ prefix() ]))
116         .pipe(gap.prependText(autoGeneratedHeader))
117         .pipe(gulpif(!config.dev, csso()))
118         .pipe(gulpif(!config.dev, sourcemaps.write()))
119         .pipe(gulp.dest(config.dest.themes));
122 // rtl standard themes css compilation
123 function rtl_style_portal() {
124     return gulp.src(config.src.styles.style_portal)
125         .pipe(gap.prependText('$dir: rtl;\n@import "rtl";\n@import "directional";\n')) // watch out for this relative path!
126         .pipe(gap.appendText('@include if-rtl { @include rtl_style; @include portal_style; }\n'))
127         .pipe(injector.replace('// bs4import', '@import "oemr-rtl";'))
128         .pipe(sourcemaps.init())
129         .pipe(sass().on('error', sass.logError))
130         .pipe(postcss([ prefix() ]))
131         .pipe(gap.prependText(autoGeneratedHeader))
132         .pipe(gulpif(!config.dev, csso()))
133         .pipe(gulpif(!config.dev, sourcemaps.write()))
134         .pipe(rename({ prefix: "rtl_" }))
135         .pipe(gulp.dest(config.dest.themes));
138 // rtl standard themes css compilation
139 function rtl_style_uni() {
140     return gulp.src(config.src.styles.style_uni)
141         .pipe(gap.prependText('$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
142         .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
143         .pipe(injector.replace('// bs4import', '@import "../oemr-rtl";'))
144         .pipe(sourcemaps.init())
145         .pipe(sass().on('error', sass.logError))
146         .pipe(postcss([ prefix() ]))
147         .pipe(gap.prependText(autoGeneratedHeader))
148         .pipe(gulpif(!config.dev, csso()))
149         .pipe(gulpif(!config.dev, sourcemaps.write()))
150         .pipe(rename({ prefix: "rtl_" }))
151         .pipe(gulp.dest(config.dest.themes));
154 // rtl color themes css compilation
155 function rtl_style_color() {
156     return gulp.src(config.src.styles.style_color)
157         .pipe(gap.prependText('$dir: rtl;\n@import "../rtl";\n')) // watch out for this relative path!
158         .pipe(gap.appendText('@include if-rtl { @include rtl_style; #bigCal { border-right: 1px solid $black !important; } }\n'))
159         .pipe(injector.replace('// bs4import', '@import "../oemr-rtl";'))
160         .pipe(sourcemaps.init())
161         .pipe(sass().on('error', sass.logError))
162                 .pipe(postcss([ prefix() ]))
163         .pipe(gap.prependText(autoGeneratedHeader))
164         .pipe(gulpif(!config.dev, csso()))
165         .pipe(gulpif(!config.dev, sourcemaps.write()))
166         .pipe(rename({ prefix: "rtl_" }))
167         .pipe(gulp.dest(config.dest.themes));
170 // rtl standard themes css compilation
171 function rtl_style_tabs() {
172     return gulp.src(config.src.styles.style_tabs)
173         .pipe(gap.prependText('$dir: rtl;\n@import "rtl";\n')) // watch out for this relative path!
174         .pipe(sourcemaps.init())
175         .pipe(sass().on('error', sass.logError))
176         .pipe(postcss([ prefix() ]))
177         .pipe(gap.prependText(autoGeneratedHeader))
178         .pipe(gulpif(!config.dev, csso()))
179         .pipe(gulpif(!config.dev, sourcemaps.write()))
180         .pipe(rename({ prefix: "rtl_" }))
181         .pipe(gulp.dest(config.dest.themes));
184 // compile themes
185 const styles = gulp.parallel(styles_style_color, styles_style_uni, styles_style_portal, styles_style_tabs, rtl_style_color, rtl_style_uni, rtl_style_portal, rtl_style_tabs);
187 // Copies (and distills, if possible) assets from node_modules to public/assets
188 function install(done) {
189     // combine dependencies and napa sources into one object
190     const dependencies = packages.dependencies;
191     for (let key in packages.napa) {
192         if (packages.napa.hasOwnProperty(key)) {
193             dependencies[key] = packages.napa[key];
194         }
195     }
197     for (let key in dependencies) {
198         // check if the property/key is defined in the object itself, not in parent
199         if (dependencies.hasOwnProperty(key)) {
200             if (key == 'dwv') {
201                 // dwv is special and need to copy dist, decoders and locales
202                 gulp.src('node_modules/' + key + '/dist/**/*')
203                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
204                 gulp.src('node_modules/' + key + '/decoders/**/*')
205                     .pipe(gulp.dest(config.dist.assets + key + '/decoders'));
206                 gulp.src('node_modules/' + key + '/locales/**/*')
207                     .pipe(gulp.dest(config.dist.assets + key + '/locales'));
208             } else if (key == 'bootstrap' || key == 'bootstrap-rtl') {
209                 // bootstrap and bootstrap-v4-rtl are special and need to copy dist and scss
210                 gulp.src('node_modules/' + key + '/dist/**/*')
211                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
212                 gulp.src('node_modules/' + key + '/scss/**/*')
213                     .pipe(gulp.dest(config.dist.assets + key + '/scss'));
214             } else if (key == '@fortawesome/fontawesome-free') {
215                 // @fortawesome/fontawesome-free is special and need to copy css, scss, and webfonts
216                 gulp.src('node_modules/' + key + '/css/**/*')
217                     .pipe(gulp.dest(config.dist.assets + key + '/css'));
218                 gulp.src('node_modules/' + key + '/scss/**/*')
219                     .pipe(gulp.dest(config.dist.assets + key + '/scss'));
220                 gulp.src('node_modules/' + key + '/webfonts/**/*')
221                     .pipe(gulp.dest(config.dist.assets + key + '/webfonts'));
222             } else if (key == '@ttskch/select2-bootstrap4-theme') {
223                 // @ttskch/select2-bootstrap4-theme is special and need to copy dist and src
224                 //  modify src/layout.scss in order for sass build to work by removing:
225                 //   @import "~bootstrap/scss/functions";
226                 //   @import "~bootstrap/scss/variables";
227                 //   @import "~bootstrap/scss/mixins";
228                 gulp.src('node_modules/' + key + '/dist/**/*')
229                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
230                 gulp.src('node_modules/' + key + '/src/**/*')
231                     .pipe(gulp.dest(config.dist.assets + key + '/src'))
232                     .on('end', function() {
233                         replace({
234                             files: config.dist.assets + key + '/src/layout.scss',
235                             from:
236                                 [
237                                     /@import "~bootstrap\/scss\/functions";/,
238                                     /@import "~bootstrap\/scss\/variables";/,
239                                     /@import "~bootstrap\/scss\/mixins";/
240                                 ],
241                             to: '',
242                         });
243                     });
244             } else if (fs.existsSync('node_modules/' + key + '/dist')) {
245                 // only copy dist directory, if it exists
246                 gulp.src('node_modules/' + key + '/dist/**/*')
247                     .pipe(gulp.dest(config.dist.assets + key + '/dist'));
248             } else {
249                 // copy everything
250                 gulp.src('node_modules/' + key + '/**/*')
251                     .pipe(gulp.dest(config.dist.assets + key));
252             }
253         }
254     }
256     done();
259 function watch() {
260     // watch all changes and re-run styles
261     gulp.watch('./interface/**/*.scss', { interval: 1000, mode: 'poll' }, styles);
263         // watch php separately since autoprefix is not needed
264         gulp_watch('./interface/themes/*.php', { ignoreInitial: false })
265                 .pipe(gulp.dest(config.dest.themes));
267     // watch all changes to css files in themes and
268         // autoprefix them before copying to public
269     return gulp_watch('./interface/themes/*.css', { ignoreInitial: false })
270                 .pipe(postcss([ prefix() ]))
271         .pipe(gulp.dest(config.dest.themes));
274 function sync() {
275     // copy all leftover root-level components to the theme directory
276     // hoping this is only temporary
277         // Copy php file separately since we don't need to autoprefix them
278         gulp.src(['interface/themes/*.php'])
279         .pipe(gulp.dest(config.dest.themes));
281         // Copy CSS files and autoprefix them
282     return gulp.src(['interface/themes/*.css'])
283                 .pipe(postcss([ prefix() ]))
284         .pipe(gulp.dest(config.dest.themes));
287 // Export watch task
288 exports.watch = watch;
290 // Export pertinent default task
291 // - Note that the default task runs if no other task is chosen,
292 //    which is generally how this script is always used (except in
293 //    rare case where the user is running the watch task).
294 if (config.install) {
295     exports.default = gulp.series(install)
296 } else {
297     exports.default = gulp.series(clean, ingest, styles, sync);