UNPKG

catalyst-frontend

Version:

A configurable frontend build pipeline that caters for everything from simple SASS compilation only, right through to ES2015 plus React.

377 lines (344 loc) 11.6 kB
'use strict'; const Generator = require('yeoman-generator'); const mkdirp = require('mkdirp'); const kebabCase = require('lodash.kebabcase'); module.exports = class extends Generator { constructor(args, opts) { super(args, opts); this.packages = [ 'autoprefixer', 'babel-eslint', // unfortunately a dep of eslint-config-airbnb-es5 even if we're not using babel :/ 'eslint', 'eslint-config-airbnb-es5', 'eslint-plugin-react', // unfortunately a dep of eslint-config-airbnb-es5 even if we're not using react :/ 'cssnano', 'gulp@^4.0.0', 'gulp-eslint', 'gulp-if', 'gulp-postcss', 'gulp-sass', 'gulp-sourcemaps', 'gulp-stylelint', 'postcss-flexbugs-fixes', 'stylelint', 'stylelint-config-sass-guidelines', 'stylelint-config-standard', ]; this.projectPackages = []; this.props = this.options.reconfigure ? {} : this.config.getAll(); // convert legacy 'tether' option to new name, 'tooltips' if (typeof(this.props.tether) === "boolean") { this.props.tooltips = this.props.tether; } } prompting() { const prompts = [ { 'type': 'confirm', 'name': 'index', 'message': `Do you want an index.html file created?`, 'default': false, 'when': typeof(this.props.index) !== "boolean" }, { 'type': 'confirm', 'name': 'browsersync', 'message': `Do you want to use Browsersync (auto page reloading server/proxy)?`, 'default': true, 'when': typeof(this.props.browsersync) !== "boolean" }, { 'type': 'list', 'name': 'browsersyncproxy', 'message': 'Do you need Browsersync to proxy your existing dev env?', 'choices': [ { 'name': 'Yes, proxy to my existing environment', 'short': 'Use Browsersync as a proxy', 'value': true }, { 'name': 'No, just serve my project directly', 'short': 'Use Browsersync to serve my files', 'value': false } ], 'when': answers => { return typeof(this.props.browsersyncproxy) !== "boolean" && (answers.browsersync === true || this.props.browsersync === true); } }, { 'type': 'input', 'name': 'browsersyncproxyaddress', 'message': 'What is the address of your local dev env to proxy?', 'default': 'http://localhost:8080', 'when': answers => { return !this.props.browsersyncproxyaddress && (answers.browsersyncproxy === true || this.props.browsersyncproxy === true); } }, { 'type': 'confirm', 'name': 'bootstrap', 'message': `Do you want to add Bootstrap to your project?`, 'default': false, 'when': typeof(this.props.bootstrap) !== "boolean" }, { 'type': 'list', 'name': 'bootstrap4', 'message': `Which version of Bootstrap do you want to use?`, 'choices': [ { 'name': 'Bootstrap 4', 'short': '4', 'value': true }, { 'name': 'Bootstrap 3', 'short': '3', 'value': false } ], 'when': answers => { return typeof(this.props.bootstrap4) !== "boolean" && (answers.bootstrap === true || this.props.bootstrap === true); } }, { 'type': 'list', 'name': 'js', 'message': 'Do you want JavaScript build support?', 'choices': [ { 'name': 'No, just SASS compilation please', 'short': 'No JS support', 'value': false }, { 'name': 'Yes, I want to process my JS files into a bundle (single JS file)', 'short': 'JS support', 'value': true } ], 'when': typeof(this.props.js) !== "boolean" }, { 'type': 'list', 'name': 'flatStructure', 'message': 'Do you want to keep your compiled and uncompiled files in separate trees, or use a flat structure?', 'choices': [ { 'name': 'In seperate nested trees, e.g. /myproject/src/scss and /myproject/dist/css', 'short': 'Nested', 'value': false }, { 'name': 'In a flat structure, e.g. /myproject/scss and /myproject/css', 'short': 'Flat', 'value': true } ], 'when': answers => { return (answers.js === false || this.props.js === false) && (typeof(this.props.flatStructure) !== "boolean"); } }, { 'type': 'input', 'name': 'src', 'message': 'Name of the directory where your uncompiled files will live:', 'default': answers => { if (answers.flatStructure || this.props.flatStructure) { return 'scss'; } return 'src'; }, 'filter': input => kebabCase(input), 'when': !this.props.src && !this.props.flatStructure }, { 'type': 'input', 'name': 'dist', 'message': 'Name of the directory where your built files will be written:', 'default': answers => { if (answers.flatStructure || this.props.flatStructure) { return 'css'; } return 'dist'; }, 'filter': input => kebabCase(input), 'validate': (input, answers) => { if (input === answers.src) { return "Folder names for uncompiled and built files must be different."; } return true; }, 'when': !this.props.dist && !this.props.flatStructure }, { 'type': 'confirm', 'name': 'jquery', 'message': 'Do you want to add jQuery into your JavaScript bundle?', 'default': true, 'when': answers => { return (answers.js || this.props.js) && (typeof(this.props.jquery) !== "boolean"); } }, { 'type': 'confirm', 'name': 'bootstrapjs', 'message': `Do you want to add Bootstrap's JS into your JavaScript bundle?`, 'default': true, 'when': answers => { return ((answers.js || this.props.js) && (answers.bootstrap || this.props.bootstrap) && (answers.jquery || this.props.jquery) && (typeof(this.props.bootstrapjs) !== "boolean")); } }, { 'type': 'confirm', 'name': 'tooltips', 'message': `Do you want to use Bootstrap's tooltips?`, 'default': false, 'when': answers => { return (answers.bootstrapjs || this.props.bootstrapjs) && (typeof(this.props.tooltips) !== "boolean"); } }, { 'type': 'confirm', 'name': 'drupalbootstrap', 'message': `Are you using Drupal and Drupal's Bootstrap theme?`, 'default': false, 'when': answers => { return ((!answers.bootstrap4 && !this.props.bootstrap4) && (answers.bootstrap || this.props.bootstrap) && (typeof(this.props.drupalbootstrap) !== "boolean")); } } ]; return this.prompt(prompts).then(props => { this.props = Object.assign({}, this.props, props); }); } configuring() { if (this.props.browsersync) { this.packages.push('browser-sync'); } if (this.props.js) { this.packages.push('gulp-uglify'); this.packages.push('gulp-concat'); } if (this.props.jquery) { this.projectPackages.push('jquery'); } if (this.props.bootstrap4) { this.projectPackages.push('bootstrap'); } else if (this.props.bootstrap) { this.projectPackages.push('bootstrap-sass'); } if (this.props.bootstrap4 && this.props.tooltips) { this.projectPackages.push('popper.js'); } else if (this.props.tooltips) { this.projectPackages.push('tether'); } } writing() { let scssPath = this.props.flatStructure ? `${this.props.src}` : `${this.props.src}/scss`; let distOrRootPath = this.props.flatStructure ? '' : `${this.props.dist}/`; this.fs.copyTpl( this.templatePath('package.json'), this.destinationPath('package.json'), {options: this.props, name: this.options.name} ); this.fs.copyTpl( this.templatePath('.editorconfig'), this.destinationPath('.editorconfig'), {options: this.props} ); this.fs.copyTpl( this.templatePath('.eslintrc.json'), this.destinationPath('.eslintrc.json') ); this.fs.copyTpl( this.templatePath('example.stylelintrc'), this.destinationPath('.stylelintrc') ); this.fs.copyTpl( this.templatePath('gulpfile.js'), this.destinationPath('gulpfile.js'), {options: this.props} ); this.fs.copyTpl( this.templatePath('README.md'), this.destinationPath('README.md'), {options: this.props, name: this.options.name} ); this.fs.copyTpl( this.templatePath('example.gitignore'), this.destinationPath('.gitignore'), {options: this.props} ); this.fs.copyTpl( this.templatePath('example.gitattributes'), this.destinationPath('.gitattributes'), {options: this.props} ); if (this.props.index) { this.fs.copyTpl( this.templatePath('index.html'), this.destinationPath(`${distOrRootPath}index.html`), { name: this.options.name, options: this.props } ); } if (!this.props.drupalbootstrap) { this.fs.copyTpl( this.templatePath('scss/index.scss'), this.destinationPath(`${scssPath}/index.scss`), {options: this.props} ); this.fs.copyTpl( this.templatePath('scss/_variables-project.scss'), this.destinationPath(`${scssPath}/_variables-project.scss`) ); } if (this.props.bootstrap && !this.props.drupalbootstrap) { this.fs.copyTpl( this.templatePath('scss/_variables-bootstrap.scss'), this.destinationPath(`${scssPath}/_variables-bootstrap.scss`), {options: this.props} ); } this.config.set(Object.assign({}, this.config.getAll(), this.props)); } install() { if (!this.props.flatStructure) { mkdirp(`${this.props.src}/scss`); mkdirp(`${this.props.src}/fonts`); mkdirp(`${this.props.src}/img`); if (this.props.js) { mkdirp(`${this.props.src}/js`); } } else if (this.props.bootstrap && !this.props.bootstrap4) { // Make a fonts folder. mkdirp('fonts'); } this.npmInstall(this.packages, {'save-dev': true}); this.npmInstall(this.projectPackages, {'save-dev': false}); } end() { if (this.props.bootstrap && !this.props.bootstrap4) { // Copy over the Bootstrap 3 fonts. if (!this.props.flatStructure) { this.spawnCommandSync( 'cp', ['-r', 'node_modules/bootstrap-sass/assets/fonts/bootstrap', `${this.props.src}/fonts`] ); } else if (!this.props.drupalbootstrap) { this.spawnCommandSync( 'cp', ['-r', 'node_modules/bootstrap-sass/assets/fonts/bootstrap', 'fonts'] ); } } if (this.props.drupalbootstrap) { // Copy Bootstrap 3 assets to local folder for Drupal. // https://drupal-bootstrap.org/api/bootstrap/starterkits!sass!README.md/group/sub_theming_sass/8 this.spawnCommandSync( 'cp', ['-r', 'node_modules/bootstrap-sass/.', 'bootstrap'] ); } } };