Upgrading an old angularJS 1.x
project with custom grunt
tasks to webpack
requires many changes, but it is absolutely worth it.
A angularJS 1.x
projectin production built with grunt
is slow. The project has over 8mb in source code, and grunt
takes over 15 seconds to build on my 2012 machine with i5 and 16GB of ram.
Besides, angularJS 1.x
is old - it is designed when JavaScript
did not have a standard to manage dependencies. angularJS 1.x
has its own dependency injection scheme, and that is completely replaced by ES6 import/export
in angular 2+
. A partial rewrite is neccessary in every scenario.
However, I need a game plan and validation before ripping everything apart due to the size of the project. Luckly, I use the same toolchain for both professional and personal projects, and I decided to use medicr.us as the guinea pig.
medicr.us is divided into "pages" and "modules". While they both are angularJS 1.x
modules, each page folder is independent and serves a single purpose, while modules are reusable pieces shared by pages.
├── src│ ├── pages│ │ ├── page1│ │ │ ├── index.js│ │ │ ├── template.jade│ │ │ └── styles.scss│ │ └── page2│ │ ├── index.js│ │ ├── template.jade│ │ └── styles.scss│ └── modules│ ├── module1│ | ├── index.js│ | ├── feature1.js│ | ├── feature1.jade│ | ├── feature1.scss│ | ├── feature2.js│ | ├── feature2.jade│ | └── feature2.scss│ └── module2│ ├── index.js│ ├── feature1.js│ ├── feature1.jade│ ├── feature1.scss│ ├── feature2.js│ ├── feature2.jade│ └── feature3.scss└── dist
To build the project, custom grunt
tasks scan the folders for all the javascripts and concatenate them together. The index.js
is always the first to be concatenated because it contains the angularJS 1.x
module definition.
SCSS
files are simply concated into one file with no specific order and passed to the processor.
angularJS 1.x
templates are stored in separate jade
files. A custom grunt
task would read the each inidividual template, process it to html
, transform the content into javascript
that wraps everything in a $templateCache.put()
call, and append the the content to the index.js
of the folder.
For example:
h1 Hello {{foo}}!
Now becomes:
angular;
First, all the javascript
files have to rewritten. ES6 import/export
statements will be handling the dependencies , instead of relying on angularJS 1.x
to manage dependency injections. Each feature.js
file will now export itself.
/** * Using feature1.js as example directive */;// jade is renamed pug due to trademark dispute; { return template: template restrict: 'E' scope: {} { // do stuff } ;};
The index.js
for each module glues all the feature files togther.
/** * Using module1 as example */; const MODULE_NAME = 'module1'; ;;; angular; exports default MODULE_NAME;
The index.js
for each page will now serve as the entry.
/** * Example webpack config */const path = ; const PAGE_FOLDER = path; moduleexports = entry: 'page1': path 'page2': path ;
/** * Using page1 as an example */;; const MODULE_NAME = 'PAGE_1'; ;;; ; exports default MODULE_NAME;
The performance imporvement after eplacing grunt
and angularJS 1.x
dependency injection with webpack
and ES6 export/import
statement is drastic. medicr.us is small, so the difference isn't noticeable. However, the ~8mb project that used to take over 15 seconds to build now only take less that 2 seconds for a cold start. Subsequnet builds take less than 500ms!
This alone is worth the 2 weeks dedicated to rewriting each file. I created a python
script to help automate most of the rewrite, but the lack of tests proves to be a major bottleneck in getting the project to production shape.
I have over 10 years of experince making web applications with technologies such as Java, C#, Python, PostgreSQL, JavaScript, etc. If you have interesting ideas, and you are looking for someone to help you bring your vision to life, shoot me a message:
[email protected]