JavaScript build workflow
Lessons learned
Piotr Lewandowski
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
- Treat git dependencies like registry dependencies.
- Front-end asset installer.
- 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
- calc checksum of package.json
- make tarball of installed deps
- 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
JavaScript build workflow
By Piotr Lewandowski
JavaScript build workflow
Lessons learned form JavaScript build process in big project, developed for 1.5+ years. Jenkins tips included.
- 1,214