Journey to webpack, part 4 - the components

New to the series? Start at the beginning

In part 3 we took care of our 3rd party libraries. Now, it’s time to deal with our 2nd party libraries.

What’s a 2nd party library?

Glad you asked - it’s the name I’ve given to libraries created by teams you collaborate with within your organization. This is usually where shared components and services go. Aside: Sharing is always complicated. At what point does something get promoted to shared status? Everyone likes to think that what they are building is going to be used by millions of people, or at least everyone in their department. But starting off building something in the shared space is tricky. Does it support everyone’s use cases? How long before it is used by more than one team? We’ve had shared implementations of stuff that was never even used! I try to push for a simple rule where nothing gets promoted into shared until the 2nd team needs it. This works pretty well most of the time, but has the downside of all teams needing to know what each other has built. Oh you have a Google Analytics service too? Yep, currently we have 5 of them. The bright side of this is that the requirements of each are well defined. Now we can take a look at all the functionality of each and try to boil it down into a single service. Easier said than done, of course. But I digress… We’ve got libraries for handling language, logging, buttons, modals, and pokerchips. Currently these files get uglified into app-components.min.js.

new entry point

So, let’s create a new entry point file that will process these and call it app-components.ts. It will will look like this:

import ‘../node_modules/app-angular-logging/dist/js/app-angular-logging’;
import ‘../node_modules/app-angular-language/dist/js/app-angular-language’;
import ‘../node_modules/app-angular-utilities/dist/js/app-angular-utilities’;
import ‘../node_modules/app-angular-meta/dist/app-angular-meta’;
import ‘../node_modules/app-angular-ui-alert/dist/js/app-angular-ui-alert’;
import ‘../node_modules/app-angular-ui-button/dist/js/app-angular-ui-button’;
import ‘../node_modules/app-angular-ui-card/dist/js/app-angular-ui-card’;
import ‘../node_modules/app-angular-ui-containers/dist/js/app-angular-ui-containers’;
import ‘../node_modules/app-angular-ui-dashboard/dist/js/app-angular-ui-dashboard’;
import ‘../node_modules/app-angular-ui-form/dist/js/app-angular-ui-form’;
import ‘../node_modules/app-angular-ui-loading/dist/js/app-angular-ui-loading’;
import ‘../node_modules/app-angular-ui-pokerchip/dist/js/app-angular-ui-pokerchip’;
import ‘../node_modules/app-angular-ui-modal/dist/js/app-angular-ui-modal’;
import ‘../node_modules/app-angular-ui-popover/dist/js/app-angular-ui-popover’;
import ‘../node_modules/app-angular-ui-select/dist/js/app-angular-ui-select’;
import ‘../node_modules/app-angular-ui-tabs/dist/js/app-angular-ui-tabs’;
import ‘../node_modules/app-angular-ui-slidein/dist/js/app-angular-ui-slidein’;
import ‘../node_modules/app-shared/dist/app-shared’;
import ‘../node_modules/app-angular-time/dist/js/app-angular-time.shared’;

Here’s what our config looks like now

output: {
filename: ‘build/static/app/vendor/js/vendor.min.js’
},
entry: {
vendor: ‘./webpack-config/vendor.ts’
},

We need to add a new entry point, but we only have one output filename. Luckily webpack comes with a variable substitution mechanism that uses [name]. To take advantage of this, we’ll change entry.vendor to contain more of the destination, like this:

output: {
filename: ‘build/static/app/vendor/js/[name]‘
},
entry: {
‘vendor.min.js’: ‘./webpack-config/vendor.ts’,
},

Cool, that still work. Now we just need to add an entry for app-components.min.js

output: {
filename: ‘build/static/app/vendor/js/[name]‘
},
entry: {
‘vendor.min.js’: ‘./webpack-config/vendor.ts’,
‘app-components.min.js’: ‘./webpack-config/app-components.ts’,
},

Errrr.. not so fast. Now app-components.min.js is being output into vendor/js/. Clearly not what we want. Luckily, webpack has your back. It takes whatever you put as the key in the entry object as the [name] to substitute. Check this out:

output: {
filename: ‘build/static/app/[name]‘
},

entry: {
‘vendor/js/vendor.min.js’: ‘./webpack-config/vendor.ts’,
‘app-components.min.js’: ‘./webpack-config/app-components.ts’,
},

YES! This results in exactly what we need:

build/static/app/vendor/js/vendor.min.js
build/static/app/app-components.min.js

Next, we can go and remove the ‘uglify:components’ from our list of Grunt tasks! Now we can make a commit and relish in the glory of making our build process a slightly nicer place.

recap

Our homegrown components and libraries “just work” with webpack. Looking back, it would have been far less frustrating to start with these, but who knew? Here is our updated webpack.config.js Looking back at our TODO list, there is still much to do:

  1. Create vendor.min.js
  2. Create app-components.min.js
  3. Create app.min.js
  4. Create templates.app.min.js
  5. Try out webpack 3.0!
  6. Figure out what’s up with moment.js
  7. Use the webpack’d files in karma for unit tests
  8. Try the CommonChunksPlugin
  9. Handle CSS/LESS/SASS
  10. Use the dev-server instead of grunt-contrib-connect