From e039d70cf3c6b35f0f8f0f109a580748b11f8088 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Sun, 12 Jun 2016 23:34:54 -0400 Subject: [PATCH 1/7] Mostly doc changes, .sass support fixes #97 , fixes #93 , fixes #90 --- ISSUE_TEMPLATE.md | 20 ++++++++++++++++++++ README.md | 14 ++++++++++++-- gulpfile.js | 11 +++++++++-- package.json | 14 +++++++------- 4 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..0fdfb22 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,20 @@ +### Issue Description +[Explain] + +### APEX Front-End Boost Version +[Example: v2.1.1] + +### Operating System +[Example: Windows] + +### Node Version +[Example: v4.4.5] + +### Browser +[Example: Chrome v50] + +### APEX Version +[Example: v5.0.3] + +### Web Server +[Example: ORDS 3.0.3, Tomcat 7] diff --git a/README.md b/README.md index e2d2c3c..6c3ced8 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,21 @@ Thanks to [Insum Solutions](http://insum.ca/) for sponsoring this project. - [Oracle APEX](https://apex.oracle.com) 4-5 (or more) for [Application Setup Option 2](/docs/apex-setup.md) ## Install -On the command line: + +#### via Git +```bash +git clone https://github.com/OraOpenSource/apex-frontend-boost.git +cd apex-frontend-boost +npm install +``` + +#### via npm ```bash npm install apex-frontend-boost ``` +*Note: installing via npm automatically creates a `\node_modules\` directory and installs APEX Front-End Boost within. Please use only if you understand what that entails, otherwise use the Git method.* + *Having problems installing on Windows? [See documentation](/docs/windows.md).* *Having problems installing on Linux? [See documentation](/docs/linux.md).* @@ -71,7 +81,7 @@ Review the [APEX Setup](/docs/apex-setup.md) docs to choose the most appropriate - Launch `apex-frontend-boost.bat` - Enter project name -**Running on Linux/OSx?** +**Running on Linux/OS X?** - Execute `./apex-frontend-boost.sh` - Enter project name diff --git a/gulpfile.js b/gulpfile.js index df467ee..da828e3 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -87,6 +87,7 @@ var paths = { js: path.normalize('/js/'), css: path.normalize('/css/'), scss: path.normalize('/scss/'), + sass: path.normalize('/sass/'), less: path.normalize('/less/'), img: path.normalize('/img/'), lib: path.normalize('/lib/') @@ -96,6 +97,7 @@ var paths = { js: path.normalize('*.js'), css: path.normalize('*.css'), scss: path.normalize('*.scss'), + sass: path.normalize('*.sass'), less: path.normalize('*.less'), all: path.normalize('*.*'), }, @@ -153,12 +155,15 @@ gulp.task('js-browsersync', ['js'], function() { browsersync.reload(); }); -// scss +// style gulp.task('style', function() { var sourceFiles; if (config.sass.enabled) { - sourceFiles = paths.src + assets.scss + files.scss; + sourceFiles = [ + paths.src + assets.scss + files.scss, + paths.src + assets.sass + files.sass + ]; } else if (config.less.enabled) { sourceFiles = paths.src + assets.less + files.less; } else { @@ -242,12 +247,14 @@ gulp.task('watch', function() { var jsWatch = (config.browsersync.enabled ? ['js-browsersync'] : ['js']); gulp.watch(allSubFolders + files.js, { cwd: paths.src + assets.js }, jsWatch); gulp.watch(allSubFolders + files.scss, { cwd: paths.src + assets.scss }, ['style']); + gulp.watch(allSubFolders + files.sass, { cwd: paths.src + assets.sass }, ['style']); gulp.watch(allSubFolders + files.less, { cwd: paths.src + assets.less }, ['style']); gulp.watch(allSubFolders + files.css, { cwd: paths.src + assets.css }, ['style']); // theme roller support if (config.themeroller.enabled) { gulp.watch(allSubFolders + files.scss, { cwd: paths.src + assets.scss }, ['themeroller']); + gulp.watch(allSubFolders + files.sass, { cwd: paths.src + assets.sass }, ['themeroller']); gulp.watch(allSubFolders + files.less, { cwd: paths.src + assets.less }, ['themeroller']); } diff --git a/package.json b/package.json index 9a252f9..8b1a476 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "apex-frontend-boost", "author": "OraOpenSource", - "version": "2.1.0", + "version": "2.1.1", "description": "Enhance your productivity with a complete Front-End Stack for Oracle APEX development", "license": "MIT", "keywords": [ @@ -27,7 +27,7 @@ "postinstall": "node generateConfig.js" }, "dependencies": { - "browser-sync": "2.12.x", + "browser-sync": "2.13.x", "del": "2.2.x", "gulp": "3.9.x", "gulp-autoprefixer": "3.1.x", @@ -40,17 +40,17 @@ "gulp-plumber": "1.1.x", "gulp-rename": "1.2.x", "gulp-sass": "2.3.x", - "gulp-less": "3.0.x", + "gulp-less": "3.1.x", "gulp-size": "2.1.x", "gulp-sourcemaps": "2.0.0-alpha", "gulp-uglify": "1.5.x", "gulp-util": "3.0.x", "gulp-clone": "1.0.x", - "gulp-header": "1.7.x", + "gulp-header": "1.8.x", "jshint": "2.x", - "jshint-stylish": "2.1.x", - "run-sequence": "1.1.x", - "yargs": "4.6.x", + "jshint-stylish": "2.2.x", + "run-sequence": "1.2.x", + "yargs": "4.7.x", "node.extend": "1.1.x", "merge-stream": "1.0.x", "rtlcss": "2.0.x", From 09988603217452e95c417f63d3e3e0a184c4adf9 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Sun, 12 Jun 2016 23:58:25 -0400 Subject: [PATCH 2/7] standardized docs tables fixes #82 --- docs/config.json.md | 110 +++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/docs/config.json.md b/docs/config.json.md index 2678de4..f1e551f 100644 --- a/docs/config.json.md +++ b/docs/config.json.md @@ -75,28 +75,21 @@ It is only mandatory to fill out the `appURL` in `config.json`. The rest is opti ## Read below for more information about each fields. -### Application +### Global -**`appURL`** : `string`, default `` -> This is the URL to your APEX application homepage. - -**`srcFolder`** : `string`, default `src` -> This is the path to your application src folder. -> If nothing is filled, the current repository will be used with the `/src/` folder. -> This is the URL to your APEX application homepage. - -**`distFolder`** : `string`, default `dist` -> This is the path to your application dist folder. -> If nothing is filled, the current repository will be used with the `/dist/` folder. +Name | Type | Default | Description +--- | --- | -- | +`appURL` | string | | This is the URL to your APEX application homepage. +`srcFolder` | string | `src` | This is the path to your application src folder. If nothing is filled, the current repository will be used with the `/src/` folder. This is the URL to your APEX application homepage. +`distFolder` | string | `dist` | This is the path to your application dist folder. If nothing is filled, the current repository will be used with the `/dist/` folder. ### Header -**`header.enabled`** : `boolean`, default `false` -> Turns on and off the automatic header comment block feature. +Name | Type | Default | Description +-- | -- | -- | -- +`header.enabled` | boolean | `false` | Turns on and off the automatic header comment block feature. +`header.packageJsonPath` | string | | Represents the path to your project's `package.json` file. Only applies if `header.enabled` is `true`. -**`header.packageJsonPath`** : `string` -> Represents the path to your project's `package.json` file. -> Only applies if `header.enabled` is `true`. > Will output a standardized comment block at the start of `js` and `css` files. > Example: ```js @@ -110,77 +103,60 @@ It is only mandatory to fill out the `appURL` in `config.json`. The rest is opti ### Javascript Concatenation -**`jsConcat.enabled`** : `boolean`, default `false` -> Turns on and off the javascript concatenation feature. - -**`jsConcat.finalName`** : `string`, default `app` -> Represents the name of the final file, after concatenation. -> Only applies if `jsConcat.enabled` is `true`. -> Will become `app.js` and `app.min.js` +Name | Type | Default | Description +-- | -- | -- | -- +`jsConcat.enabled` | boolean | `false` | Turns on and off the javascript concatenation feature. +`jsConcat.finalName` | string | `app` | Represents the name of the final file, after concatenation. Only applies if `jsConcat.enabled` is `true`. Will become `app.js` and `app.min.js` ### CSS Concatenation -**`cssConcat.enabled`** : `boolean`, default `false` -> Turns on and off the css concatenation feature. - -**`cssConcat.finalName`** : `string`, default `app` -> Represents the name of the final file, after concatenation. -> Only applies if `cssConcat.enabled` is `true`. -> Will become `app.css` and `app.min.css` +Name | Type | Default | Description +-- | -- | -- | -- +`cssConcat.enabled` | boolean | `false` | Turns on and off the javascript concatenation feature. +`cssConcat.finalName` | string | `app` | Represents the name of the final file, after concatenation. Only applies if `cssConcat.enabled` is `true`. Will become `app.css` and `app.min.css` ### Sass -**`sass.enabled`** : `boolean`, default `false` -> Turns on and off the sass parsing feature. - -**`sass.includePath`** : `string` -> Include a path to an external sass folder. Allows to use the `@import` feature from within that folder. +Name | Type | Default | Description +-- | -- | -- | -- +`sass.enabled` | boolean | `false` | Turns on and off the sass parsing feature. +`sass.includePath` | string | | Include a path to an external sass folder. Allows to use the `@import` feature from within that folder. -*When using Sass, please ensure that Less is turned off.* +> When using Sass, please ensure that Less is turned off. ### Less -**`less.enabled`** : `boolean`, default `false` -> Turns on and off the less parsing feature. - -**`less.includePath`** : `string` -> Include a path to an external less folder. Allows to use the `@import` feature from within that folder. +Name | Type | Default | Description +-- | -- | -- | -- +`less.enabled` | boolean | `false` | Turns on and off the less parsing feature. +`less.includePath` | string | | Include a path to an external less folder. Allows to use the `@import` feature from within that folder. -*When using Less, please ensure that Sass is turned off.* +> When using Less, please ensure that Sass is turned off. ### Browsersync -**`browsersync.enabled`** : `boolean`, default `false` -> Turns on and off the browsersync feature. +Name | Type | Default | Description +-- | -- | -- | -- +`browsersync.enabled` | boolean | `false` | Turns on and off the browsersync feature. +`browsersync.port` | int | `3000` | This is the port that browsersync uses to serve your static files. +`browsersync.uiPort` | int | `3001` | Browsersync includes a user-interface that is accessed via a separate port. +`browsersync.weinrePort` | int | `8080` | This is the weinre port that browsersync uses. +`browsersync.notify` | boolean | `true` | This option makes browsersync alert you when a file is dynamically injected to you browser. -**`browsersync.port`** : `int`, default `3000` -> This is the port that browsersync uses to serve your static files. - -**`browsersync.uiPort`** : `int`, default `3001` -> Browsersync includes a user-interface that is accessed via a separate port. - -**`browsersync.weinrePort`** : `int`, default `8080` -> This is the weinre port that browsersync uses. - -**`browsersync.notify`** : `boolean`, default `true` -> This option makes browsersync alert you when a file is dynamically injected to you browser. > Useful for Javascript & CSS development, as you won't have to manually refresh your browser. ### Theme Roller -**`themeroller.enabled`** : `boolean`, default `false` -> Turns on and off the Theme Roller feature. This will generate a `less` file that you can import into your application theme style. It will add editable variables to theme roller. - -**`themeroller.finalName`** : `string`, default `themeroller` -> Represents the name of the final less file, after concatenation from the array `themeroller.paths`. -> Only applies if `themeroller.enabled` is `true`. - -**`themeroller.paths`** : `array` -> Include the order of `scss` files to be parsed by theme roller. +Name | Type | Default | Description +-- | -- | -- | -- +`themeroller.enabled` | boolean | `false` | Turns on and off the Theme Roller feature. This will generate a `less` file that you can import into your application theme style. It will add editable variables to theme roller. +`themeroller.finalName` | string | `themeroller` | Represents the name of the final less file, after concatenation from the array `themeroller.paths`. Only applies if `themeroller.enabled` is `true`. `themeroller.paths` | array | | Include the order of `scss` files to be parsed by theme roller. ### RTLCSS -**`rtl.enabled`** : `boolean`, default `false` -> Turns on and off automatic `css` transformation from Left-To-Right (LTR) to Right-To-Left (RTL) languages. +Name | Type | Default | Description +-- | -- | -- | -- +`rtl.enabled` | boolean | `false` | Turns on and off automatic `css` transformation from Left-To-Right (LTR) to Right-To-Left (RTL) languages. + > Produces a `.rtl` version of your css files > Example: `app.css` also produces `app.rtl.css` From b7bb47973fd7d4995b8e8a3d97f6e32b8e866b53 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Wed, 15 Jun 2016 15:47:02 -0400 Subject: [PATCH 3/7] added image optimization feature fixes #53 --- README.md | 2 ++ default.json | 3 +++ docs/config.json.md | 11 +++++++++++ gulpfile.js | 1 + package.json | 1 + 5 files changed, 18 insertions(+) diff --git a/README.md b/README.md index 6c3ced8..c7697bc 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ APEX Front-End Boost is a personal local web server that hosts and distributes y - Generates APEX Theme Roller configuration. *(optional)* - Transforms `css` to RTL format. *(optional)* - Adds a standardized header comment block to `js` and `css` files. *(optional)* +- Minifies images seamlessly *(optional)* ## How APEX Front-End Boost helps you - Cut down on front-end development time. @@ -119,6 +120,7 @@ APEX Front-End Boost will automatically compile your files to this folder struct - [Sourcemaps](https://www.npmjs.com/package/gulp-sourcemaps) - [Header](https://github.com/tracker1/gulp-header) - [RTLCSS](https://github.com/MohammadYounes/rtlcss) +- [imagemin](https://github.com/sindresorhus/gulp-imagemin) - More... [See features examples](/docs/examples.md). diff --git a/default.json b/default.json index d8251b2..0836d00 100644 --- a/default.json +++ b/default.json @@ -36,5 +36,8 @@ }, "rtl": { "enabled": false + }, + "imageOptimization": { + "enabled": false } } diff --git a/docs/config.json.md b/docs/config.json.md index f1e551f..3516c6c 100644 --- a/docs/config.json.md +++ b/docs/config.json.md @@ -69,6 +69,9 @@ It is only mandatory to fill out the `appURL` in `config.json`. The rest is opti }, "rtl": { "enabled": false + }, + "imageOptimization": { + "enabled": false } } ``` @@ -160,3 +163,11 @@ Name | Type | Default | Description > Produces a `.rtl` version of your css files > Example: `app.css` also produces `app.rtl.css` + +### Image Optimization + +Name | Type | Default | Description +-- | -- | -- | -- +`imageOptimization.enabled` | boolean | `false` | Turns on and off automatic image lossless optimizers. + +> Minifies images in the `/img/` folder. diff --git a/gulpfile.js b/gulpfile.js index da828e3..25f3877 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -205,6 +205,7 @@ gulp.task('style', function() { // copy img files as is gulp.task('img', function() { return gulp.src(paths.src + assets.img + allSubFolders + files.all) + .pipe(plugins.if(config.imageOptimization.enabled, plugins.imagemin())) .pipe(gulp.dest(paths.dist + assets.img)); }); diff --git a/package.json b/package.json index 8b1a476..60fe3c7 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "gulp-util": "3.0.x", "gulp-clone": "1.0.x", "gulp-header": "1.8.x", + "gulp-imagemin": "3.0.x", "jshint": "2.x", "jshint-stylish": "2.2.x", "run-sequence": "1.2.x", From a8d7154d4e7e275befdc0e9c96288755efa89d55 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Fri, 17 Jun 2016 09:46:20 -0400 Subject: [PATCH 4/7] Better error handling fixes #101, fixes #98 --- default.json | 8 +-- docs/config.json.md | 11 ++-- gulpfile.js | 74 +++++++++++++----------- lib/defaultSchema.json | 128 +++++++++++++++++++++++++++++++++++++++++ lib/util.js | 17 +++++- package.json | 117 ++++++++++++++++++------------------- 6 files changed, 253 insertions(+), 102 deletions(-) create mode 100644 lib/defaultSchema.json diff --git a/default.json b/default.json index 0836d00..1849667 100644 --- a/default.json +++ b/default.json @@ -2,10 +2,6 @@ "appURL": "", "srcFolder": "src", "distFolder": "dist", - "header": { - "enabled": false, - "packageJsonPath": "" - }, "jsConcat": { "enabled": false, "finalName": "app" @@ -34,6 +30,10 @@ "finalName": "themeroller", "files" : [] }, + "header": { + "enabled": false, + "packageJsonPath": "" + }, "rtl": { "enabled": false }, diff --git a/docs/config.json.md b/docs/config.json.md index 3516c6c..50a668e 100644 --- a/docs/config.json.md +++ b/docs/config.json.md @@ -35,10 +35,6 @@ It is only mandatory to fill out the `appURL` in `config.json`. The rest is opti "appURL": "", "srcFolder": "src", "distFolder": "dist", - "header": { - "enabled": false, - "packageJsonPath": "" - }, "jsConcat": { "enabled": false, "finalName": "app" @@ -67,6 +63,10 @@ It is only mandatory to fill out the `appURL` in `config.json`. The rest is opti "finalName": "themeroller", "files" : [] }, + "header": { + "enabled": false, + "packageJsonPath": "" + }, "rtl": { "enabled": false }, @@ -98,7 +98,8 @@ Name | Type | Default | Description ```js /*! * apex-frontend-boost - Enhance your productivity with a complete Front-End Stack for Oracle APEX development - * @version v2.0.0 + * @author OraOpenSource + * @version v2.2 * @link https://github.com/OraOpenSource/apex-frontend-boost * @license MIT */ diff --git a/gulpfile.js b/gulpfile.js index 25f3877..e903ea4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,61 +14,67 @@ var gulp = require('gulp'), util = require('./lib/util'), scssToLess = require('./lib/scssToLess'), rtlcss = require('./lib/rtlcss'); - + validate = require('jsonschema').validate, + schema = require('./lib/defaultSchema'), + fs = require("fs"); // 2. PREREQUISITES AND ERROR HANDLING -var defaultConfig = require('./default'), - userConfig = require('./config'), - config = extend(true, {}, defaultConfig, userConfig[argv.project]); -// command line syntax -if (typeof argv.project == "undefined") { - console.log("The correct syntax is: npm start -- --project=yourProjectName"); - process.exit(1); -} +// read the user config.json +var userConfigJSON = fs.readFileSync("config.json"); -// project exists -if (typeof userConfig[argv.project] == "undefined") { - console.log("Project", argv.project ,"doesn't exists in your config.json file."); - process.exit(1); +// validates if user config.json is valid JSON +if (!util.isValidJSON(userConfigJSON)) { + console.log("Your config.json file is not a valid JSON object."); + console.log("Try using a JSON Linter such as: http://jsonlint.com/"); + process.exit(); } -// sass or less, not both -if (config.sass.enabled && config.less.enabled) { - console.log("Choose either Sass or Less (not both) as the CSS preprocessor for project", argv.project); - process.exit(1); +// validates command line syntax +if (typeof argv.project == "undefined") { + console.log("The correct syntax is: npm start -- --project=yourProjectName"); + process.exit(); } -// missing project appURL -if (util.isEmptyObject(config.appURL)) { - console.log("Missing appURL in your config.json file."); -} +// import default config and user config +var defaultConfig = require('./default'), + userConfig = require('./config'); -// missing project srcFolder -if (util.isEmptyObject(config.srcFolder)) { - console.log("Missing srcFolder in your config.json file."); +// validate if project exists +if (typeof userConfig[argv.project] == "undefined") { + console.log("Project", argv.project, "doesn't exist in your config.json file."); + process.exit(); } -// missing project distFolder -if (util.isEmptyObject(config.distFolder)) { - console.log("Missing distFolder in your config.json file."); +// user config json schema validation +var userConfigSchema = validate(userConfig[argv.project], schema); +if (userConfigSchema.errors.length > 0) { + console.log("Your config.json file is not valid. See errors below:"); + console.log(userConfigSchema.errors.map(function(elem){ + return (elem.property + " " + elem.message).replace("instance", argv.project); + }).join("\n")); + process.exit(); } -if((util.isEmptyObject(config.appURL)) -|| (util.isEmptyObject(config.srcFolder)) -|| (util.isEmptyObject(config.distFolder))) { - process.exit(1); +// merge default config with user config +var config = extend(true, {}, defaultConfig, userConfig[argv.project]); + +// sass or less, not both +if (config.sass.enabled && config.less.enabled) { + console.log("Choose either Sass or Less (not both) as the CSS preprocessor for project", argv.project); + process.exit(); } // missing project header.packageJsonPath if (config.header.enabled) { if (util.isEmptyObject(config.header.packageJsonPath)) { console.log("Missing packageJsonPath in your config.json file."); - process.exit(1); + process.exit(); } else { var pkg = require(config.header.packageJsonPath + "package.json"); var banner = ['/*!', ' * <%= pkg.name %> - <%= pkg.description %>', + ' * @author v<%= pkg.author %>', ' * @version v<%= pkg.version %>', ' * @link <%= pkg.homepage %>', ' * @license <%= pkg.license %>', @@ -170,6 +176,7 @@ gulp.task('style', function() { sourceFiles = paths.src + assets.css + files.css; } + // creates the source stream that will be used for unmin and min versions var sourceStream = gulp.src(sourceFiles) .pipe(plugins.plumber()) .pipe(plugins.if(config.header.enabled, plugins.header(banner, { pkg : pkg } ))) @@ -178,12 +185,14 @@ gulp.task('style', function() { .pipe(plugins.if(config.less.enabled, plugins.less(lessOptions))) .pipe(plugins.if(config.cssConcat.enabled, plugins.concat(config.cssConcat.finalName + '.css'))); + // creates the unmin css var unmin = sourceStream .pipe(plugins.clone()) .pipe(plugins.autoprefixer()) .pipe(plugins.size(sizeOptions)) .pipe(plugins.sourcemaps.write(paths.sourcemaps)); + // creates the min css var min = sourceStream .pipe(plugins.clone()) .pipe(plugins.autoprefixer()) @@ -192,6 +201,7 @@ gulp.task('style', function() { .pipe(plugins.size(sizeOptions)) .pipe(plugins.sourcemaps.write(paths.sourcemaps)); + // adds the unmin and the min version to the stream return merge(unmin, min) .pipe(clip()) .pipe(gulp.dest(paths.dist + assets.css)) diff --git a/lib/defaultSchema.json b/lib/defaultSchema.json new file mode 100644 index 0000000..52d9ca0 --- /dev/null +++ b/lib/defaultSchema.json @@ -0,0 +1,128 @@ +{ + "type": "object", + "properties": { + "appURL": { + "type": "string" + }, + "srcFolder": { + "type": "string" + }, + "distFolder": { + "type": "string" + }, + "jsConcat": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "finalName": { + "type": "string" + } + } + }, + "cssConcat": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "finalName": { + "type": "string" + } + } + }, + "sass": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "includePath": { + "type": "string" + } + } + }, + "less": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "includePath": { + "type": "string" + } + } + }, + "browsersync": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + }, + "uiPort": { + "type": "integer" + }, + "weinrePort": { + "type": "integer" + }, + "notify": { + "type": "boolean" + } + } + }, + "themeroller": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "finalName": { + "type": "string" + }, + "files": { + "type": "array", + "items": {} + } + } + }, + "header": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "packageJsonPath": { + "type": "string" + } + }, + "required": [ + "packageJsonPath" + ] + }, + "rtl": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "imageOptimization": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + } + }, + "required": [ + "appURL", + "srcFolder", + "distFolder" + ] +} diff --git a/lib/util.js b/lib/util.js index feebc9e..4ddeacf 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,5 +1,16 @@ module.exports = { - isEmptyObject: function (obj) { - return !Object.keys(obj).length; - } + // validates if an object is empty (true), otherwise (false) + isEmptyObject: function(obj) { + return !Object.keys(obj).length; + }, + + // parses the user config.json and validates json + isValidJSON: function(obj) { + try { + JSON.parse(obj); + return true; + } catch (e) { + return false; + } + } }; diff --git a/package.json b/package.json index 60fe3c7..874f72a 100644 --- a/package.json +++ b/package.json @@ -1,60 +1,61 @@ { - "name": "apex-frontend-boost", - "author": "OraOpenSource", - "version": "2.1.1", - "description": "Enhance your productivity with a complete Front-End Stack for Oracle APEX development", - "license": "MIT", - "keywords": [ - "oracle", - "apex", - "orclapex", - "css", - "javascript", - "front-end", - "responsive", - "framework", - "web" - ], - "repository": { - "type": "git", - "url": "https://github.com/OraOpenSource/apex-frontend-boost.git" - }, - "bugs": { - "url": "https://github.com/OraOpenSource/apex-frontend-boost/issues" - }, - "scripts": { - "start": "gulp", - "postinstall": "node generateConfig.js" - }, - "dependencies": { - "browser-sync": "2.13.x", - "del": "2.2.x", - "gulp": "3.9.x", - "gulp-autoprefixer": "3.1.x", - "gulp-clip-empty-files": "0.1.x", - "gulp-concat": "2.6.x", - "gulp-if": "2.0.x", - "gulp-jshint": "2.0.x", - "gulp-load-plugins": "1.2.x", - "gulp-cssnano": "2.1.x", - "gulp-plumber": "1.1.x", - "gulp-rename": "1.2.x", - "gulp-sass": "2.3.x", - "gulp-less": "3.1.x", - "gulp-size": "2.1.x", - "gulp-sourcemaps": "2.0.0-alpha", - "gulp-uglify": "1.5.x", - "gulp-util": "3.0.x", - "gulp-clone": "1.0.x", - "gulp-header": "1.8.x", - "gulp-imagemin": "3.0.x", - "jshint": "2.x", - "jshint-stylish": "2.2.x", - "run-sequence": "1.2.x", - "yargs": "4.7.x", - "node.extend": "1.1.x", - "merge-stream": "1.0.x", - "rtlcss": "2.0.x", - "through2": "2.0.x" - } + "name": "apex-frontend-boost", + "author": "OraOpenSource", + "version": "2.1.1", + "description": "Enhance your productivity with a complete Front-End Stack for Oracle APEX development", + "license": "MIT", + "keywords": [ + "oracle", + "apex", + "orclapex", + "css", + "javascript", + "front-end", + "responsive", + "framework", + "web" + ], + "repository": { + "type": "git", + "url": "https://github.com/OraOpenSource/apex-frontend-boost.git" + }, + "bugs": { + "url": "https://github.com/OraOpenSource/apex-frontend-boost/issues" + }, + "scripts": { + "start": "gulp", + "postinstall": "node generateConfig.js" + }, + "dependencies": { + "browser-sync": "2.13.x", + "del": "2.2.x", + "gulp": "3.9.x", + "gulp-autoprefixer": "3.1.x", + "gulp-clip-empty-files": "0.1.x", + "gulp-concat": "2.6.x", + "gulp-if": "2.0.x", + "gulp-jshint": "2.0.x", + "gulp-load-plugins": "1.2.x", + "gulp-cssnano": "2.1.x", + "gulp-plumber": "1.1.x", + "gulp-rename": "1.2.x", + "gulp-sass": "2.3.x", + "gulp-less": "3.1.x", + "gulp-size": "2.1.x", + "gulp-sourcemaps": "2.0.0-alpha", + "gulp-uglify": "1.5.x", + "gulp-util": "3.0.x", + "gulp-clone": "1.0.x", + "gulp-header": "1.8.x", + "gulp-imagemin": "3.0.x", + "jshint": "2.x", + "jshint-stylish": "2.2.x", + "run-sequence": "1.2.x", + "yargs": "4.7.x", + "node.extend": "1.1.x", + "merge-stream": "1.0.x", + "rtlcss": "2.0.x", + "through2": "2.0.x", + "jsonschema": "1.1.x" + } } From 0a86c63385f869dfd9512930e926a4167133d7c6 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Fri, 17 Jun 2016 16:18:14 -0400 Subject: [PATCH 5/7] added colors to CLI and creates srcFolder automatically fixes #100 --- gulpfile.js | 69 +++++++++++++++++++++++++++++++++++----------------- package.json | 20 ++++++++------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index e903ea4..470fc1b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -16,7 +16,10 @@ var gulp = require('gulp'), rtlcss = require('./lib/rtlcss'); validate = require('jsonschema').validate, schema = require('./lib/defaultSchema'), - fs = require("fs"); + fs = require("fs"), + mkdirp = require('mkdirp'); + +const chalk = require('chalk'); // 2. PREREQUISITES AND ERROR HANDLING @@ -25,14 +28,14 @@ var userConfigJSON = fs.readFileSync("config.json"); // validates if user config.json is valid JSON if (!util.isValidJSON(userConfigJSON)) { - console.log("Your config.json file is not a valid JSON object."); - console.log("Try using a JSON Linter such as: http://jsonlint.com/"); + console.log(chalk.red.bold("Your config.json file is not a valid JSON object.")); + console.log(chalk.red.bold("Try using a JSON Linter such as: http://jsonlint.com/")); process.exit(); } // validates command line syntax if (typeof argv.project == "undefined") { - console.log("The correct syntax is: npm start -- --project=yourProjectName"); + console.log(chalk.red.bold("The correct syntax is: npm start -- --project=yourProjectName")); process.exit(); } @@ -42,14 +45,14 @@ var defaultConfig = require('./default'), // validate if project exists if (typeof userConfig[argv.project] == "undefined") { - console.log("Project", argv.project, "doesn't exist in your config.json file."); + console.log(chalk.red.bold("Project", argv.project, "doesn't exist in your config.json file.")); process.exit(); } // user config json schema validation var userConfigSchema = validate(userConfig[argv.project], schema); if (userConfigSchema.errors.length > 0) { - console.log("Your config.json file is not valid. See errors below:"); + console.log(chalk.red.bold("Your config.json file is not valid. See errors below:")); console.log(userConfigSchema.errors.map(function(elem){ return (elem.property + " " + elem.message).replace("instance", argv.project); }).join("\n")); @@ -61,26 +64,21 @@ var config = extend(true, {}, defaultConfig, userConfig[argv.project]); // sass or less, not both if (config.sass.enabled && config.less.enabled) { - console.log("Choose either Sass or Less (not both) as the CSS preprocessor for project", argv.project); + console.log(chalk.red.bold("Choose either Sass or Less (not both) as the CSS preprocessor for project", argv.project)); process.exit(); } // missing project header.packageJsonPath if (config.header.enabled) { - if (util.isEmptyObject(config.header.packageJsonPath)) { - console.log("Missing packageJsonPath in your config.json file."); - process.exit(); - } else { - var pkg = require(config.header.packageJsonPath + "package.json"); - var banner = ['/*!', - ' * <%= pkg.name %> - <%= pkg.description %>', - ' * @author v<%= pkg.author %>', - ' * @version v<%= pkg.version %>', - ' * @link <%= pkg.homepage %>', - ' * @license <%= pkg.license %>', - ' */', - ''].join('\n'); - } + var pkg = require(config.header.packageJsonPath + "package.json"); + var banner = ['/*!', + ' * <%= pkg.name %> - <%= pkg.description %>', + ' * @author v<%= pkg.author %>', + ' * @version v<%= pkg.version %>', + ' * @link <%= pkg.homepage %>', + ' * @license <%= pkg.license %>', + ' */', + ''].join('\n'); } // 3. SETTINGS VARIABLES @@ -131,6 +129,30 @@ var paths = { next(); }; +// build directory structure +// js img and lib are mandatory +var dirs = [ + paths.src + assets.js, + paths.src + assets.img, + paths.src + assets.lib +]; + +// sass less and css are based on user config +if (config.sass.enabled || config.less.enabled) { + if (config.sass.enabled) { + dirs.push(paths.src + assets.scss); + } else { + dirs.push(paths.src + assets.less); + } +} else { + dirs.push(paths.src + assets.css); +} + +// create directory structure if doesn't exist yet +for (var i = 0; i < dirs.length; i++) { + mkdirp.sync(dirs[i]); +} + // 4. TASKS // cleans the dist directory gulp.task('clean-dist', function() { @@ -291,6 +313,9 @@ gulp.task('default', function() { // run tasks runSequence('clean-dist', tasks, 'watch', function() { - console.log("APEX Front-End Boost has successfully processed your files."); + console.log(chalk.green.bold("APEX Front-End Boost has successfully processed your files.")); + console.log(chalk.cyan.bold("Now open up your favorite code editor and modify any file within:")); + console.log(dirs); + console.log(chalk.cyan.bold("All files belonging in the directories above are made available to use in APEX")); }); }); diff --git a/package.json b/package.json index 874f72a..3e7a1e5 100644 --- a/package.json +++ b/package.json @@ -28,34 +28,36 @@ }, "dependencies": { "browser-sync": "2.13.x", + "chalk": "1.1.x", "del": "2.2.x", "gulp": "3.9.x", "gulp-autoprefixer": "3.1.x", "gulp-clip-empty-files": "0.1.x", + "gulp-clone": "1.0.x", "gulp-concat": "2.6.x", + "gulp-cssnano": "2.1.x", + "gulp-header": "1.8.x", "gulp-if": "2.0.x", + "gulp-imagemin": "3.0.x", "gulp-jshint": "2.0.x", + "gulp-less": "3.1.x", "gulp-load-plugins": "1.2.x", - "gulp-cssnano": "2.1.x", "gulp-plumber": "1.1.x", "gulp-rename": "1.2.x", "gulp-sass": "2.3.x", - "gulp-less": "3.1.x", "gulp-size": "2.1.x", "gulp-sourcemaps": "2.0.0-alpha", "gulp-uglify": "1.5.x", "gulp-util": "3.0.x", - "gulp-clone": "1.0.x", - "gulp-header": "1.8.x", - "gulp-imagemin": "3.0.x", "jshint": "2.x", "jshint-stylish": "2.2.x", - "run-sequence": "1.2.x", - "yargs": "4.7.x", - "node.extend": "1.1.x", + "jsonschema": "1.1.x", "merge-stream": "1.0.x", + "mkdirp": "0.5.x", + "node.extend": "1.1.x", "rtlcss": "2.0.x", + "run-sequence": "1.2.x", "through2": "2.0.x", - "jsonschema": "1.1.x" + "yargs": "4.7.x" } } From 3764af7577177d9e287d148899813ec26c111456 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Mon, 20 Jun 2016 12:05:02 -0400 Subject: [PATCH 6/7] Enhanced docs, preparing 2.1.1 release fixes #94 , fixes #102 , fixes #103 --- ISSUE_TEMPLATE.md | 3 +++ README.md | 13 ++++++++++--- changelog.md | 11 +++++++++++ docs/cors.md | 16 ++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 docs/cors.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 0fdfb22..2a8de96 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -18,3 +18,6 @@ ### Web Server [Example: ORDS 3.0.3, Tomcat 7] + +### Your `config.json` file +[Paste code] diff --git a/README.md b/README.md index c7697bc..ebb4248 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Thanks to [Insum Solutions](http://insum.ca/) for sponsoring this project. - [Oracle APEX](https://apex.oracle.com) 5 (or more) for [Application Setup Option 1](/docs/apex-setup.md) - [Oracle APEX](https://apex.oracle.com) 4-5 (or more) for [Application Setup Option 2](/docs/apex-setup.md) +*Note: Having `Cross Origin Sharing Requests` issues? [See CORS documentation](/docs/cors.md).* + ## Install #### via Git @@ -76,16 +78,21 @@ There are two options to setup your application: Review the [APEX Setup](/docs/apex-setup.md) docs to choose the most appropriate option for your project. ## Run -`npm start -- --project=yourProjectName` +**On the command line:** +```bash +npm start -- --project=yourProjectName +``` -**Running on Windows?** +**or use Windows shortcut:** - Launch `apex-frontend-boost.bat` - Enter project name -**Running on Linux/OS X?** +**or use Linux/OS X shortcut:** - Execute `./apex-frontend-boost.sh` - Enter project name +*Note: If you encounter errors while executing the steps above, you may need to use an elevated command line (run as administrator).* + ## Usage From the `src` folder you can create, edit or delete any files in: ``` diff --git a/changelog.md b/changelog.md index fd1f144..e6d9647 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,15 @@ # Changelog +## 2.1.1 +- Greatly enhanced the project error handling to provide more details and hints to the user. +- The `/src/` folder is now automatically created if it doesn't exist yet. +- Added `.sass` file support in addition to the existing `.scss` support. +- Docs: Added a documentation notice on ORDS issues. +- Docs: Added an advice to use an elevated command line (run as admin). +- Docs: Changed some of the project terminology. +- Docs: Provided two different installation options (Git and npm). +- Docs: Enhanced the documentation for `config.json` +- Created project issue template for better support going forward. + ## 2.1.0 - Project is now available on npm - Fixed a bug preventing from doing POST on Chrome diff --git a/docs/cors.md b/docs/cors.md new file mode 100644 index 0000000..a23fa36 --- /dev/null +++ b/docs/cors.md @@ -0,0 +1,16 @@ +## Cross Origin Sharing Requests + +Starting from ORDS `3.0.3`, we have seen this issue when running APEX applications with APEX Front-End Boost: + +> 403 Forbidden +> The request cannot be processed because this resource does not support Cross Origin Sharing requests, or the request Origin is not authorized to access this resource. If ords is being reverse proxied ensure the front end server is propagating the host name, for mod_proxy ensure ProxyPreserveHost is set to On + +This occurs when the server is using ORDS `3.0.3`, `3.0.4` or `3.0.5`. + +It does **NOT** occur when using ORDS `3.0.2` or less. + +Hopefully that will be fixed in future ORDS version, until then please use ORDS `3.0.2` or less. + +Here are some related forum topics: +- https://community.oracle.com/thread/3906326 +- https://community.oracle.com/message/13659147 From 4fd71880ac5baf4a292f372fec973e784f269c97 Mon Sep 17 00:00:00 2001 From: Vincent Morneau Date: Tue, 21 Jun 2016 07:33:29 -0400 Subject: [PATCH 7/7] more doc enhancements fixes #104 --- README.md | 52 +++++++++++++++++++++++++++++++++++++++++++++------- docs/cors.md | 6 +++--- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ebb4248..ed1b6cc 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,33 @@ [![Build Status](https://travis-ci.org/OraOpenSource/apex-frontend-boost.svg?branch=master)](https://travis-ci.org/OraOpenSource/apex-frontend-boost) [![Dependency Status](https://david-dm.org/OraOpenSource/apex-frontend-boost.svg)](https://david-dm.org/OraOpenSource/apex-frontend-boost) -APEX Front-End Boost makes coding faster, easier, and prettier. This productivity tool helps you work with static files (`js`, `css`, `images`, etc.) more efficiently within an APEX application. - +- [What APEX Front-End Boost is](#what-apex-front-end-boost-is) + - [What APEX Front-End Boost does](#what-apex-front-end-boost-does) + - [How APEX Front-End Boost helps you](#how-apex-front-end-boost-helps-you) + - [Other benefits](#other-benefits) +- [Project Sponsors](#project-sponsors) +- [System Requirements](#system-requirements) +- [Install](#install) + - [via Git](#via-git) + - [via npm](#via-npm) +- [Upgrade](#upgrade) + - [via Git](#via-git) + - [via npm](#via-npm) +- [Configuration](#configuration) +- [APEX Application Setup](#apex-application-setup) +- [Run](#run) +- [Usage](#usage) +- [Features](#features) +- [Changelog](#changelog) + +## What APEX Front-End Boost is APEX Front-End Boost is a personal local web server that hosts and distributes your files to your APEX application. +APEX Front-End Boost makes coding faster, easier, and prettier. This productivity tool helps you work with static files (`js`, `css`, `images`, etc.) more efficiently within an APEX application. + ![demo](/media/demo-main.gif) -## What APEX Front-End Boost does +#### What APEX Front-End Boost does - Minifies `js` and `css`. - Generates `js` and `css` sourcemaps. - Adds `css` vendor prefixes. @@ -20,7 +40,7 @@ APEX Front-End Boost is a personal local web server that hosts and distributes y - Adds a standardized header comment block to `js` and `css` files. *(optional)* - Minifies images seamlessly *(optional)* -## How APEX Front-End Boost helps you +#### How APEX Front-End Boost helps you - Cut down on front-end development time. - Enhance your application performance due to smaller file sizes. - Keep coding in your favorite code editor, without having to constantly upload anything to APEX or a web server. @@ -28,6 +48,7 @@ APEX Front-End Boost is a personal local web server that hosts and distributes y - Stop affecting other developers. **Any development done within APEX Front-End Boost affects you and only you**. - Be notified of `js` and `css` errors as you save. +#### Other benefits It makes responsive development easier by synchronizing multiple devices together. Your desktop, tablet and mobile device will imitate each others actions (scrolling, clicking, typing) as long as you've got APEX Front-End Boost running. It eliminates the need for refreshing the browser. As soon as you save your code in the text editor, you get automatic code injection / reloading in the browser. @@ -40,9 +61,11 @@ Thanks to [Insum Solutions](http://insum.ca/) for sponsoring this project. - [Oracle APEX](https://apex.oracle.com) 5 (or more) for [Application Setup Option 1](/docs/apex-setup.md) - [Oracle APEX](https://apex.oracle.com) 4-5 (or more) for [Application Setup Option 2](/docs/apex-setup.md) -*Note: Having `Cross Origin Sharing Requests` issues? [See CORS documentation](/docs/cors.md).* +*Having `Cross Origin Sharing Requests` issues? [See CORS documentation](/docs/cors.md).* ## Install +- Open the command line +- Go to the APEX Front-End Boost directory #### via Git ```bash @@ -62,6 +85,22 @@ npm install apex-frontend-boost *Having problems installing on Linux? [See documentation](/docs/linux.md).* +## Upgrade +- Open the command line +- Go to your APEX Front-End Boost directory + +#### via Git +```bash +git fetch origin +git reset --hard origin/master +npm install +``` + +#### via npm +```bash +npm install apex-frontend-boost +``` + ## Configuration You need to configure APEX Front-End Boost for your project(s). [See documentation](/docs/config.json.md). @@ -114,8 +153,7 @@ APEX Front-End Boost will automatically compile your files to this folder struct |-lib ``` -### Self-Signed SSL Browser Warning -[See documentation](/docs/ssl-warning.md). +*Having problems regarding Self-Signed SSL Browser Warning? [See documentation](/docs/ssl-warning.md).* ## Features - [Browsersync](http://www.browsersync.io/) diff --git a/docs/cors.md b/docs/cors.md index a23fa36..8dd493e 100644 --- a/docs/cors.md +++ b/docs/cors.md @@ -1,15 +1,15 @@ ## Cross Origin Sharing Requests -Starting from ORDS `3.0.3`, we have seen this issue when running APEX applications with APEX Front-End Boost: +Starting from ORDS `3.0.3`, a new security rule concerning `Cross Origin Sharing Requests` conflicts with APEX Front-End Boost when using a VM through port forwarding: > 403 Forbidden > The request cannot be processed because this resource does not support Cross Origin Sharing requests, or the request Origin is not authorized to access this resource. If ords is being reverse proxied ensure the front end server is propagating the host name, for mod_proxy ensure ProxyPreserveHost is set to On This occurs when the server is using ORDS `3.0.3`, `3.0.4` or `3.0.5`. -It does **NOT** occur when using ORDS `3.0.2` or less. +For Apache, please follow the message and set the ProxyPreserveHost parameter to On. -Hopefully that will be fixed in future ORDS version, until then please use ORDS `3.0.2` or less. +Otherwise until then please use ORDS `3.0.2` or less, as the error does **NOT** occur. Here are some related forum topics: - https://community.oracle.com/thread/3906326