frontend-starter

1.12.3 • Public • Published

Frontend-starter

Frontend gulp.js-based (v4) build framework. A prepared, configurable environment available as a global package (possible to install locally as well). Automatically produces clean and optimized output code. A perfect solution for any frontend work.

Development is based on fully customizable bundles (currently available only simple default bundle), which modify the core configuration and provide directory structure. Supported JavaScript modes: script (concatenated and minified) and module (ES2015 imports via webpack).

About

The framework is intended for use in any size projects, including those that need be developed quickly, e.g in digital agencies. Produces optimized code, that contains usually single, minified JavaScript and CSS files.

What distinguishes this tool is basically:

  • core, including tasks, separated from your project code (as a global Node.js package):
    • you can update it independently and use new features
    • create your own preconfigured starter-bundles, e.g. for AngularJS, React, Wordpress or just for specific project types (e.g. clients) with common configuration
    • you don't have to run npm install and wait to initialize a project - just start coding
    • after some time you can go back to an old or other developer's project and use the same API
  • fully customizable structure, ability to setup exact directory paths (e.g. source image files can be located in ~/Somewhere/On/The/Moon/, dist HTML files in ../public_html and JavaScript files in dist/js)
  • by default, in script mode (non-webpack), a single output JavaScript file is built (app.js), also for the dev environment (with source mapping):
    • adding any new file using Bower, manually placing any package into vendor/js dir (if you can't, don't have time or just don't want to use Bower) or creating your new source script, does not require any markup changes to include new file
    • you can, however, generate separate compositions, for example: a script consisting of jQuery (installed with Bower) and a register.js file (and mark the latter one as ignored in other scripts)
    • the output generation is optimized: vendor files are watched separately and cached, so if you change your own code these are just prepended
  • automatically creates separate sprite images for src/sprites subdirectories (and you can use them responsively)
  • clean task does not remove the whole dist directory, but handles them separately; that's why you can mix your framework assets with files from other sources (e.g. backend)
  • provides keyboard shortcuts (Ctrl+...) while watching: rebuild, build production version, lint

Thanks to the above parameters, it is very easy to integrate with a backend application, including classic, non-RESTful/SPAs (Single Page Applications).

The architecture, in few words, is as follows: when you invoke the main frs [task] command, the script runs gulp in the framework directory (so it uses the core gulpfile.js), but gets the assets from (and builds to) the directories defined in your configuration files. So you can consider it as a kind of gulp pipeline.

The result: you just develop fast. Modify/create new stylesheets or images and see your page automatically refreshing with changes. Put pictures into sprites dir and get all things done. Install or paste new JavaScript files and see the results instantly, with source maps.

Features

The framework provides the following functionality via gulp plugins:

Installation (global)

You need the following tools to start using the framework:


Then, install the framework globally:

npm install frontend-starter -g

If you are experiencing any problems during installation, you probably have to update your Node.js (recommended nvm, then use the latest Node.js version) and npm. In some cases system restart may be needed before installation. If you use Visual Studio, close it while npm installs the modules.

Installation registers an frs command to run the tasks.

Installation (local)

Assuming you have Node.js installed, get the bundle (e.g. the default) and run:

npm install frontend-starter --save-dev

Then just use the script run syntax, e.g.:

npm run frs start -- -r

Note the -- separator for options (read more).

Bundles

Use on of the available bundles (bootstrap configuration and asset structure) or create your own:


CLI (tasks)

Use the following tasks from the command line:

Build & watch together

frs start

For your first run, or when you want to rebuild a clean dist version. This will run both build and watch tasks.

Watch - the default task

frs or frs watch

Gulp watches for any changes in your src directory and runs the appropiate task.

Build

frs build

Cleans and builds the dist version.

Lint

frs lint

Runs a linter (currently only ESLint).

Clean

frs clean

Cleans the dist directory.

Production

frs build -p

Add the -p parameter to any task, to get the optimized version. Or set NODE_ENV variable to production (e.g. $ NODE_ENV=production frs build).

Restart

To restart the builder without opening a new Browsersync window in the browser, add a -r parameter for the tasks: default (watch) and start, e.g.

frs -r
frs start -r

Partial tasks

styles, sprites, fonts, js, images, views, custom-dirs, browser-sync

Keyboard shortcuts

While watching for changes (tasks: frs/frs watch or frs start), you can use the following shortcuts:

  • Ctrl+P: to build the production version (init build -p task)
  • Ctrl+D: to build the development version (init build task)
  • Ctrl+L: to run lint (init lint task)
  • Ctrl+C: to exit

Functionality

Styles, Fonts, Views

See your bundle docs.

Sprites

All files placed in the sprites directory will be merged into one sprite image (by default - sprites.png). To create more than one sprite bundle, place them in separate directories (directory name will be the output sprite filename by default). Example usage:

/src/sprites/home/
  icon-1.png
  icon-2.png
/src/sprites/contact/
  icon-1.png
  icon-2.png
/src/sprites/ (root dir)
  icon-1.png
  icon-2.png

This will generate sprite files in /dist/img/ directory: home.png, contact.png and sprites.png. To use a sprite in your stylesheets, include the generated SASS file(s) and then use the mixins:

// To get /src/sprites/home/icon-1.png
@include sprite($home-icon-1);
 
// To get /src/sprites/contact/icon-2.png
@include sprite($contact-icon-2);
 
// To get /src/sprites/icon-1.png
@include sprite($icon-1);

As you can see, by default each Spritesmith generated sprite variable has a prefix equal to the directory name (except for the root dir, that has none).

You can customize any of the directories options, by adding an item explicitly in the config file. For example, this will disable a variable prefix for sprites from /home directory (so you can use it like it was in the root):

config.sprites.items.push({
  name: 'home',
  varPrepend: ''
}

See more in the default bundle example configuration.

JavaScript

For third-party scripts, you can use Bower or place any file in the /vendor/js directory. For your own code, just create any file in src/js. By default, all of them will be merged into single app.js file (in the above order).

JavaScript compositions

You can generate separate JavaScript compositions, dependent on selected Bower, vendor and/or own (app) script files. Let's say, that you want to create register.js output file, that uses jQuery, register.js and utilities.js from the sources. We assume, that we don't want these files to be included in our main app.js file:

config.js.comps.register = {
  filename: 'register', // Set to null to not produce any output file (for sub-comps); if not set, defaults to comp id
 
  bower: [],                                  // Set only name of the package
  vendor: [],                                 // Just an example, you don't have to define when not used
  app: ['utilities.js', 'register.js'],       // Path relative to the appropriate directory
 
  // Set prioritized paths
  priority: {
    vendor: [],
    app: ['utilities.js']   // This file will be included before register.js
  },
 
  // Set other comp ids to include
  dependencies: ['jQuery'],
 
  // Exclude (ignore) all loaded here scripts in other comps, e.g.
  // excludeIn: ['comp1', 'comp2']   // Excluded in selected comps
  // excludeIn: true                 // Excluded in all other comps
  // excludeIn: false                // No exclusion
  excludeIn: true,                   // Here: we exclude it in any other comps
 
  watch: true  // Not needed, watch blocked only if false
}
 
// We didn't include jQuery directly in the "register" comp, because in that case it would also be ignored in other comps
config.js.comps.jQuery: {
  filename: null,    // We don't want to create any output - this is just an auxiliary comp
  bower: ['jquery'],
  watch: false
}
 

Using ES2015 imports

The basic configuration is:

config.js.comps.main = {
  filename: 'app',      // Entry: a filename or glob, e.g. ['app', 'app2'] (.js extension appended automatically if dot not found)
  webpack: ['**/*.js']  // Files to watch; disables bower, vendor and app props
}

Remember to update the linter option:

config.lint.options.parserOptions.sourceType = 'module';

Linter

The framework uses ESLint to check the code standards and quality. By default, the JavaScript Standard Style with commas is assumed, i.e. JavaScript Semi-Standard Style.

Frontend starter comes with Semi-Standard, Standard and classic ESLint configurations (like eslint:recommended) installed. To change the base config to one of them, you have to create a .eslintrc file in you app's root directory with the following example configuration:

{
  extends: "eslint:recommended",

  parserOptions: {
    ecmaVersion: 6,
    sourceType: "module"
  }
}

Due to the ESLint architecture, you cannot change the "extends" value in an inline way (in the frs.config.js) - the configuration file is the only solution.

In the case you are using Frontend starter as a global module and want to use any other base configuration than the listed preinstalled ones (extends: "some-custom-config"), apart of the config module itself, you will have to additionally install gulp-eslint locally (npm i gulp-eslint --save-dev). This is needed because ESLint script looks for the configuration module from its location perspective - without the local installation, it would be the global framework's node_modules and would fail to load it, since it is installed locally. The framework will detect that you have a local gulp-eslint and use it instead of the preinstalled (global) one.

Images

Images are optimized (for production, gulp-imagemin) and copied into the dist directory.

Custom directories

You can setup custom directories to watch (and optionally copy). For example, if you integrate the framework with backend that has own view templating system, set the appropriate directory to be watched. In this case, you will also probably need to set Browsersync proxy (see the default bundle example configuration) to use the original server (like Apache) but have your page being refreshed on each time the view or any other files change.

Example - watch and copy contents of "php" dir from src to dist:

config.customDirs.items.push({
  name: 'php views',  // Optional, displayed in the console during watch
  src: dirs.src.main + 'php/**/*.php',
  dest: dirs.dist.main + 'php/'  // Set to null to just watch the dir without copying (e.g. external backend views)
});

Server

Browsersync provides a simple HTTP server with auto-refreshing on each change.


Directories and configuration

All configuration definitions are placed in core files: gulpfile.dirs.js and gulpfile.config.js. See the default bundle config files for common examples and the dir or config sources for full list of options. It's very simple.

To change the defaults, edit the frs.dirs.js, frs.config.js and frs.tasks.js files located in your bundle root directory.

Directories

You can see the default definitons of each directory in the gulpfile.dirs.js file. The frs.dirs.js is included in two stages:

  • right after defining the src and dist directory (so you can change it and the value will populate to subdirectories like images, styles...)
  • at the end (to change particular src/dist directories). See the default bundle dir config.

Config object

See the gulpfile.config.js file. config object contains configuration parameters divided into key sections. Use the subsets to target specific environment mode: dev and prod.

  • styles: sourcemap generation, gulp-autoprefixer, gulp-sass and gulp-cssnano options
  • sprites: you can customize sprite files by adding subsequent elements to the items array
  • js: sourcemap generation, minification, merging vendor and app into one file (true by default), scripts loading priority
  • images: imagemin options
  • views: gulp-htmlmin options
  • customDirs: custom, additional directories (to watch/copy)
  • browserSync: Browsersync options
  • clean: modify deletion options

See the default bundle custom config for examples.

Customizing core tasks

Each gulp pipeline step has a kind of hook, that allows to inject own code and/or disable default stream transformation. Consider the following configuration code for styles task:

var config = {
  // (...)
  styles: {
    // (...)
    inject: {
      src: true,    // Function must return: a stream (if cancels) or a glob array passed to the src
      sourceMapsInit: true,
      sassGlob: true,
      sass: true,
      autoprefixer: true,
      optimizeMediaQueries: false, // group-css-media-queries, disabled by default as unsafe
      optimize: true,              // cssnano
      sourceMapsWrite: true,
      dest: true,
      finish: true,
      reload: true
    },
 
    dev: {
      // (...)
      inject: {
        optimizeMediaQueries: false,
        optimize: false
      }
    }
// (...)
 

To remove any of above steps, set the inject config value to false:

config.styles.inject.optimize = false;

To add any transformation before the step, or replace it, assign it to a function:

var cleanCss = require('gulp-clean-css');
config.styles.inject.optimize = function(stream) {
  // stream: current stream
  stream = stream.pipe(cleanCss());
 
  // return stream;   // If you don't want to cancel the original step
 
  // ...but we do want to cancel the default step (cssnano)
  return this.cancel(stream);
}

This replaces gulp-cssnano with gulp-clean-css (you have to run npm install gulp-clean-css --save-dev first).

The src injects are handled a bit differenlty. The function obtains a glob array to be passed to the gulp.src. If the default step is canceled, the return value is considered as an input stream (unless it is falsy - then the whole task is canceled). In other case, the returned value must be a glob (e.g. you can change the default one), that will be used by gulp.src.

For the clean task, the inject function receives current glob array with paths to be removed (assigned incrementally).

Available properties available from within the inject function are:

  • this.task: task name
  • this.appData: an object { dirs, config, app, tasks, taskReg, gulp, browserSync }
  • this.taskParams: an object with task paramters (common param for all tasks is isWatch that indicates that it was called by the watcher; see the tasks source for other params, defined at the beginning of the run method)
  • this.taskData: an object created for some tasks with additional info:
    • sprites: { itemInfo } (current item config object)
    • js: { comp, filename, filenameVendor, vendorDir } (current internal comp object, not the comp config definition)
    • customDirs: { dirInfo } (current item config object)
  • this.isDev: indicates whether dev or prod mode

Adding/removing tasks

All tasks to be registered in gulp are organized in the taskReg object. Consider the following example definition that may be placed in the frs.tasks.js file:

appData.taskReg['mytask'] = {
  fn() {
    var stream = appData.gulp.src(appData.dirs.src.images)
      .pipe(appData.gulp.dest('/some-dir'));
 
    // You can also access config, e.g. check if dev vs. prod mode
    //console.log(appData.config.main.isDev);
 
    // Currently all tasks must return a promise
    return appData.app.taskUtils.streamToPromise(stream);
  },
  deps: ['clean', ['js', 'views']],
 
  // blockQuitOnFinish: true  // Set this option only for persistent tasks like watching for changes (by default any task function is wrapped to ensure process quitting)
}

This adds mytask task, that copies contents of images dir to somewhere.

The deps is an array of tasks invoked before. It follows the run-sequence convention: by default tasks are run synchronously (one by one), but placing them in an array will allow to run asynchronously (at once). In the above example, js and views will run in parallel after clean is complete. This notation is converted internally to gulp 4's series/parallel.

To add a task as a dependency to an existing task, use the helper:

// appData.app.taskRegUtils.addDep(taskToAdd, targetTask, relatedTask, isBefore);
appData.app.taskRegUtils.addDep('mytask', 'build', 'images', true);

The above code adds mytask to the build pipeline, before images (last parameter defines the placement, for false it would be placed after).

To replace the original (core) task, just override its appData.taskReg definition.

To remove a core task, or remove a dependency, use the helpers:

// Removes views task (and from all tasks' depenedencies)
appData.app.taskRegUtils.removeTask('views');
 
// Removes images dependency from build task
appData.app.taskRegUtils.removeDep('images', 'build');
 
// Removes images dependency from any task
appData.app.taskRegUtils.removeDep('images', true);

See the core tasks registry definitions in gulpfile.tasks.js.


Standalone (local) version

To use gulp.js directly, not through the frs command, clone this repo into a desired directory, run npm install and then directly gulp [task]. The framework will look for configuration files in the parent directory (../).


TODO

  • take advantage of cssnano, htmlmin
  • supporting Babel
  • full task customization based on hooks (injected for every task step, allowing to modify or remove it)
  • ability to register custom tasks
  • custom tasks key shortcuts
  • unit tests task
  • unit tests for the framework
  • plugins API

Readme

Keywords

Package Sidebar

Install

npm i frontend-starter

Weekly Downloads

1

Version

1.12.3

License

MIT

Unpacked Size

103 kB

Total Files

21

Last publish

Collaborators

  • implico