JavaScript build workflow

Lessons learned

Piotr Lewandowski

@constjs

npm install
npm install -g bower
bower install
npm install -g grunt
grunt

setup flow

./gradlew run

# just works
# no need to install anything

npm

gradle

do we need global dependencies?

use npm scripts

{
  "scripts": {
    "postinstall": "bower install",
    "start": "grunt",
    "release": "grunt build --release"
  }
}

+ more control on remote env
    e.g. Jenkins
 

+ all packages can be local

> npm install
> npm start

> npm run release

no more global dependencies

do we need bower?

+ flat directory tree

+ simple dependency resolution

   (simple yet effective)

+ no big problems actually

- the same work as npm

- additional tool in stack

   (needs to be learnt)

- no clear future

nope. not yet.

still missing some front-end packages*

can I switch to npm?

* you can put direct link to GitHub repo

but that's not the point

npm goals for 2016

better support for front-end flow

  1. Treat git dependencies like registry dependencies.
  2. Front-end asset installer.
  3. Support the new ECMAScript module system.

Don't install libraries

with

10 lines of code!

npm + Jenkins = ?

build = 200MB and 25k files*
         

  • Cache problems
  • Quota
  • Limit of inodes
  • Internet connection

*backend and other stuff per job = ~1GB

npm install
--no-optional
--cache-min=999999
--quiet

npm + Jenkins = ❤️

npm 3 is slightly better

  • less files
  • less space

npm 2+

npm-cache

even better for CI / Jenkins

npm install -g npm-cache

npm-cache install npm bower
  1. calc checksum of package.json
  2. make tarball of installed deps
  3. downloads deps only when package.json will change

build

we use Grunt

1000+ lines of config file

  • a bit messy

  • ... not only in config file

  • ... regular changes needed

clean config

an unexpected journey

single responsibility

one reason to change a file

 

 

separate

  • list of libraries
  • list of modules
  • encapsulated tasks
    • linters

    • optimizations

    • releases

instead of...

dashboard: {
    files: {
        'dist/js/dashboard.min.js': [
            'src/modules/dashboard/module.js',
            '!src/modules/dashboard/route.js'
            'src/modules/dashboard/**/*.js'
    ]
}

// ... repeat for 40 other modules

// ... add new tasks at the end of file

create project abstraction

  
  var APP_MODULES = [
    { module: 'modules.shop',      dir: 'shop',      outFile: 'shop.min.js' },
    { module: 'modules.dashboard', dir: 'dashboard', outFile: 'dashboard.min.js' },
    { module: 'modules.account',   dir: 'account',   outFile: 'account.min.js' }
  ];

make project files structure RegEx friendly

envoriment variables



  var properties = {
      VERSION: version,
      API: '/* @echo API */',
      TYPE: '/* @echo TYPE */',
      REVISION: '/* @echo REVISION */',
      DATE: '/* @echo DATE */'
  };
  • one file!

  • can be injected anywhere

  • can be unit tested

  • list of all possibilities
    in one place

the same rules as clean code

Gandalf approves

Gulp > Grunt


gulp.task("compile", ["tslint"], () => {
    return gulp.src("src/**/*.ts")
        .pipe(sourcemaps.init())
        .pipe(tsc(tsProject)).js
        .pipe(ngAnnotate())
        .pipe(sourcemaps.write("."))
        .pipe(gulp.dest("build"));
});

for more complex apps

+ simple API

+ code over configuration

+ easily separated for many    files

separated front-end?

... you're gonna have a bad time

+ less team communication required

+ easier setup for front-end devs

- synchronization problem

- security

single page app
=

 different security

serve resources from back-end

if your app is the only client
of your API

End Of File

Thanks

Made with Slides.com