diff --git a/CHANGELOG.md b/CHANGELOG.md index e8440d8..c15133a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,25 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +v4.3.0 +------------------------------ +*August 10, 2017* + +### Added +- Added `config.importedAssets` object. +- Added imported assets paths to pathBuilder. +- Added `copy:assets` task. +- Added `clean:assets` task. +- Added `watch:assets` task. +- Unit tests added for new config and pathBuilder properties. +- The Readme *Imported Assets config* section was added. +- The Readme *Imported Assets pathBuilder* section was added. +- The Readme was updated to document the new tasks added. + +### Changed +- Updated clean task comments. +- The `css:bundle` task loads the `importedAssetsDistDir` into postcss, so that Fozzie modules can access assets copied there. + v4.2.0 ------------------------------ *August 08, 2017* diff --git a/README.md b/README.md index a44f921..70257dc 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,14 @@ Runs the following tasks Removes any CSS already in the dist directory. +- #### `clean:assets` + + Removes any imported assets in the imported assets directory. + +- #### `copy:assets` + + Copies assets from packages to the imported assets directory. + - #### `css:bundle` Performs a variety of tasks including; @@ -229,6 +237,10 @@ Runs the [`scripts:lint`](#scriptslint) and [`scripts:test`](#scriptstest) tasks Runs the [`images`](#images) task when an image file is changed. +- #### `watch:assets` + +Runs the [`copy:assets`](#copyassets) task when when there are changes in node modules. + ### `watch:docs` Runs the same tasks as [`watch`](#watch) as well as the following watch tasks. @@ -283,6 +295,10 @@ Here is the outline of the configuration options, descriptions of each are below imgDir, svgSpriteFilename }, + importedAssets: { + importedAssetsDir, + importedAssetsSrcGlob + }, sw: { isEnabled, swDir, @@ -456,6 +472,25 @@ Root dist directory for your assets. Filename of the SVG sprite which is generated from any SVG assets found in the image directory. +### `importedAssets` + +- #### `importedAssetsDir` + + Type: `string` + + Default: `'imported-assets'` + + Name of the directory where assets from node_modules will be copied to. + +- #### `importedAssetsSrcGlob` + + Type: `string` + + Default: `'node_modules/@justeat/**/*'` + + Glob of packages containing assets to be copied to `importedAssetsDir`. Watched by [`watch:assets`](#watchassets). + + ### `sw` - #### `isEnabled` @@ -755,6 +790,11 @@ These are the paths which the `pathBuilder` object provides. Default: `'dist/img'` +- #### `importedAssetsDistDir` + + Default: `'dist/imported-assets'` + + - #### `swOutputPath` Default: `'.'` diff --git a/config.js b/config.js index 7fe4407..f48d5eb 100644 --- a/config.js +++ b/config.js @@ -47,6 +47,14 @@ const ConfigOptions = () => { svgSpriteFilename: 'sprite.svg' }, + /** + * Imported assets related variables + */ + importedAssets: { + importedAssetsDir: 'imported-assets', + importedAssetsSrcGlob: 'node_modules/@justeat/**/*' + }, + /** * Service Worker related variables */ @@ -149,6 +157,7 @@ const ConfigOptions = () => { css: Object.assign(config.css, options.css), js: Object.assign(config.js, options.js), img: Object.assign(config.img, options.img), + importedAssets: Object.assign(config.importedAssets, options.importedAssets), sw: Object.assign(config.sw, options.sw), copy: Object.assign(config.copy, options.copy), docs: Object.assign(config.docs, options.docs), diff --git a/package.json b/package.json index 786382b..e52055e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@justeat/gulp-build-fozzie", - "version": "4.2.0", + "version": "4.3.0", "description": "Gulp build tasks for use across Fozzie modules", "main": "index.js", "author": "Damian Mullins (http://www.damianmullins.com)", @@ -42,6 +42,7 @@ "exorcist": "^0.4.0", "eyeglass": "^1.2.1", "filesizegzip": "^2.0.0", + "glob": "^7.1.2", "gulp": "^3.9.1", "gulp-cached": "^1.1.1", "gulp-changed": "^3.1.0", @@ -69,6 +70,7 @@ "helper-markdown": "^1.0.0", "helper-md": "^0.2.2", "jest-cli": "^20.0.0", + "npm-assets": "^0.1.2", "postcss-assets": "^4.2.0", "postcss-reporter": "^5.0.0", "postcss-scss": "^1.0.2", diff --git a/pathBuilder.js b/pathBuilder.js index b5cf318..be1f400 100644 --- a/pathBuilder.js +++ b/pathBuilder.js @@ -16,6 +16,8 @@ const buildPaths = config => { imgSrcDir: `${config.assetSrcDir}/${config.img.imgDir}`, imgDistDir: `${config.assetDistDir}/${config.img.imgDir}`, + importedAssetsDistDir: `${config.assetDistDir}/${config.importedAssets.importedAssetsDir}`, + swOutputPath: `${config.webRootDir}`, swSrcDir: `${config.assetSrcDir}/${config.sw.swDir}`, swDistDir: `${config.assetDistDir}/${config.sw.swDir}`, diff --git a/tasks/clean.js b/tasks/clean.js index 2835b13..d1c4d81 100644 --- a/tasks/clean.js +++ b/tasks/clean.js @@ -7,7 +7,7 @@ const pathBuilder = require('../pathBuilder'); /** * `clean:css` Task * --------------------- - * Removes all files form the CSS dist directory. + * Removes all files from the CSS dist directory. * */ gulp.task('clean:css', () => del( @@ -18,7 +18,7 @@ gulp.task('clean:css', () => del( /** * `clean:scripts` Task * --------------------- - * Removes all files form the JavaScript dist directory. + * Removes all files from the JavaScript dist directory. * */ gulp.task('clean:scripts', () => del( @@ -29,7 +29,7 @@ gulp.task('clean:scripts', () => del( /** * `clean:images` Task * --------------------- - * Removes all images form the images dist directory. + * Removes all images from the images dist directory. * */ gulp.task('clean:images', () => del( @@ -37,10 +37,21 @@ gulp.task('clean:images', () => del( ); +/** + * `clean:assets` Task + * --------------------- + * Removes all imported assets from the imported assets dist directory. + * + */ +gulp.task('clean:assets', () => del( + `${pathBuilder.importedAssetsDistDir}/**/*`) +); + + /** * `clean:docs` Task * ------------- - * Removes all files form the docs dist directory. + * Removes all files from the docs dist directory. * */ gulp.task('clean:docs', () => del( diff --git a/tasks/copy.js b/tasks/copy.js index e60b079..41809a1 100644 --- a/tasks/copy.js +++ b/tasks/copy.js @@ -2,8 +2,10 @@ const gulp = require('gulp'); const gutil = require('gulp-util'); const plumber = require('gulp-plumber'); const gulpif = require('gulp-if'); - +const copyAssets = require('npm-assets'); const rev = require('gulp-rev'); +const glob = require('glob'); + const config = require('../config'); const pathBuilder = require('../pathBuilder'); @@ -81,3 +83,44 @@ gulp.task('copy:img', () => { gulp.task('copy:fonts', () => { copy('fonts'); }); + +/** + * `copy:assets` Task + * --------------------- + * Copy assets from from packages to the dist folder. + * + */ +gulp.task('copy:assets', callback => { + + const ending = 'package.json'; + const getPkg = filepath => { + const path = filepath.slice(0, -ending.length); // the parent directory that contains the package.json + const split = path.split('/'); // e.g. [...'@justeat', '', 'fozzie', ''] + return { + path, + name: split[split.length - 2] + }; + }; + + glob(config.importedAssets.importedAssetsSrcGlob, (err, files) => { + if (err) config.gulp.onError(err); + + const process = file => new Promise((resolve, reject) => { + const pkg = getPkg(file); + gutil.log(`❯❯ Copying any assets in ${pkg.path} to ${pathBuilder.importedAssetsDistDir}/${pkg.name}`); + copyAssets(pkg.path, `${pathBuilder.importedAssetsDistDir}/${pkg.name}`, e => { + if (e) { + config.gulp.onError(e); + reject(); + } else resolve(); + }); + }); + + const promises = files + .filter(file => file.endsWith(ending)) // Only consider folders containing a package.json + .map(file => process(file)); + + Promise.all(promises).then(callback); + }); + +}); diff --git a/tasks/css.js b/tasks/css.js index f7ef18a..800ba29 100644 --- a/tasks/css.js +++ b/tasks/css.js @@ -31,7 +31,8 @@ const pathBuilder = require('../pathBuilder'); gulp.task('css', callback => { runSequence( 'scss:lint', - 'clean:css', + ['clean:css', 'clean:assets'], + 'copy:assets', 'css:bundle', 'copy:css', 'css:lint', @@ -116,7 +117,7 @@ gulp.task('css:bundle', () => gulp.src(`${pathBuilder.scssSrcDir}/**/*.scss`) postcss([ // Converts any specified assets to data URIs assets({ - loadPaths: [pathBuilder.imgSrcDir] + loadPaths: [pathBuilder.imgSrcDir, pathBuilder.importedAssetsDistDir] }), // Autoprefixes CSS properties for various browsers – browsers specified in package.json config diff --git a/tasks/watch.js b/tasks/watch.js index 4c9c358..eb76355 100644 --- a/tasks/watch.js +++ b/tasks/watch.js @@ -15,7 +15,7 @@ gulp.task('watch', callback => { runSequence( 'default', - ['watch:css', 'watch:scripts', 'watch:scripts:test', 'watch:images'], + ['watch:css', 'watch:scripts', 'watch:scripts:test', 'watch:images', 'watch:assets'], callback ); @@ -83,6 +83,20 @@ gulp.task('watch:images', () => { }); +/** + * `watch:assets` Task + * ------------- + * Runs the `copy:assets` task when there are changes in node modules. + * + */ +gulp.task('watch:assets', () => { + + gulp.watch(config.importedAssets.importedAssetsSrcGlob, ['copy:assets']) + .on('change', config.gulp.changeEvent); + +}); + + /** * `watch:docs` Task * ------------- diff --git a/test/config.test.js b/test/config.test.js index 57c3a4d..d7b89e3 100644 --- a/test/config.test.js +++ b/test/config.test.js @@ -233,6 +233,40 @@ describe('image config', () => { }); }); +describe('imported assets config', () => { + + it('imported assets directory should be set', () => { + expect(config.importedAssets.importedAssetsDir).toBe('imported-assets'); + }); + + it('imported assets directory can be updated', () => { + // Arrange + const importedAssetsDir = 'imports'; + + // Act + config.update({ importedAssets: { importedAssetsDir } }); + + // Assert + expect(config.importedAssets.importedAssetsDir).toBe(importedAssetsDir); + }); + + it('imported assets source glob should be set', () => { + expect(config.importedAssets.importedAssetsSrcGlob).toBe('node_modules/@justeat/**/*'); + }); + + it('imported assets source glob can be updated', () => { + // Arrange + const importedAssetsSrcGlob = 'node_modules/**/*'; + + // Act + config.update({ importedAssets: { importedAssetsSrcGlob } }); + + // Assert + expect(config.importedAssets.importedAssetsSrcGlob).toBe(importedAssetsSrcGlob); + }); + +}); + describe('service worker config', () => { it('is enabled should be false', () => { diff --git a/test/pathBuilder.test.js b/test/pathBuilder.test.js index 9c355a2..6dea8bd 100644 --- a/test/pathBuilder.test.js +++ b/test/pathBuilder.test.js @@ -44,6 +44,14 @@ describe('image paths', () => { }); +describe('imported assets paths', () => { + + it('dist directory path should be correct', () => { + expect(pathBuilder.importedAssetsDistDir).toBe('dist/imported-assets'); + }); + +}); + describe('service worker paths', () => { it('output path should be correct', () => { diff --git a/yarn.lock b/yarn.lock index ecdb831..b2b4129 100644 --- a/yarn.lock +++ b/yarn.lock @@ -787,7 +787,7 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@1.5.2, async@^1.4.0, async@^1.5.0, async@^1.5.2: +async@1.5.2, async@^1.4.0, async@^1.5.0, async@^1.5.1, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -797,6 +797,10 @@ async@^2.1.4: dependencies: lodash "^4.14.0" +async@~0.2.9: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -4009,6 +4013,12 @@ find-index@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" +find-modules@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/find-modules/-/find-modules-0.2.0.tgz#8cf92e08a3b39141cf5b358b17b6f97efd0083a6" + dependencies: + async "~0.2.9" + find-pkg@^0.1.0, find-pkg@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/find-pkg/-/find-pkg-0.1.2.tgz#1bdc22c06e36365532e2a248046854b9788da557" @@ -7515,6 +7525,15 @@ now-and-later@^1.0.0: dependencies: once "^1.3.2" +npm-assets@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/npm-assets/-/npm-assets-0.1.2.tgz#ed943ccf1d318a3e7841ad9abe67a8396a0f179f" + dependencies: + async "^1.5.1" + find-modules "~0.2.0" + graceful-fs "^4.1.9" + mkdirp "^0.5.1" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"