CanJS builds with Webpack
by Jani Mikkonen
Long story .. ehem .. Long
Some time ago I was working on couple of different projects where our end goals where quite a bit different but we still wanted to share as much code as possible between these two projects. Since project A started a good few months earlier and working with RequireJS was what I was really familiar with, we went with that along with few other required libraries. After a brief experimentation period, i picked up CanJS as our main framework to build our app. Few months later when project B started to gain some speed. Other team had picked up Webpack with CommonJS module format over RequireJS & AMD, React & Fluxx0r instead of CanJS.
Since our honest goal as still to re-use each other’s code and other resources like CI as much as possible, it was clear that also project A should need to be converted to CommonJS and webpack so that we could re-use each other’s build tooling and other common assets.
In about a day, I had converted all of our codebase from project A into CJS and started to work on making everything build with webpack. Previously we had been using Bower to install production dependencies into a build env and NPM only for development & build dependencies. Bower package, afair for CanJS was obviously titled canjs and as a lazy guy, I thought that i could just switch from npm package with a same name, canjs. Oh boy, I was asking for trouble for not doing a proper research of the actual package.
I had already familiar with CanJS but building wasn’t really one that one of those because Bower packages where straight up AMD’s. Bitovi guys where also making their own module loader StealJS and their default module format was what ever steal is using. But still, I thought, I can crack this! I had already checked into the canjs build scripts and there where few interesting tasks relating building canjs as a cjs module. I knew I was into something here! I started to debug my webpack build procedure, what gets included, from where, in which order. I read through the canjs build scripts and eventually, i actually found it out: If i fetch the canjs code from github directly, can make cjs build on my own. But why on earth didnt canjs npm package have cjs dist folder that would be generated by a local build? Took a while to actually realize that canjs module wasn’t even really the one that was still maintained and yeah, it had this issue that published npm package did not have cjs build included in it. Bug report and correspondence with helpful Bitovi guys later, i was pointed out that CanJS’s official package is actually called “can”.
So, that was a few good days “well spend”. But yeah, i got to learn a lot about webpack and canjs’s internals in the process. And then I was ready to actually make things work.
Making the build work
Since webpack uses CommonJS format , we can just install CanJS package with it along with webpack itself:
npm install –save-dev can webpackIn typical webpack build, one usually has node_modules
resolve.modulesDirectories along with other paths and require() just finds the packages there. But as i pointed out earlier, CanJS uses steal by default and this won’t make the webpack work yet. But since we already know that there is also a cjs module being part of npm package, we can add that folder with higher priority above node_modules
`. Like this:
resolve: {
modulesDirectories: [
'src',
'node_modules/can/dist/cjs/',
'node_modules',
],
extensions: ['', '.js']
}
Next i needed to separate the vendor libraries and my application code into two separate bundles. That was a breeze with webpack’s Chunk plugin:
app: {
context: 'src/',
entry: {
app: 'index.js',
vendor: ['can']
},
output: {
path: './target',
filename: 'example.js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
]
}
And finally, we had some stache templates that we wanted to incorporate into application bundle so that everything would be served with minimal amount of requests to server. Once again, very easy to do after i found out a “raw-loader” npm module for webpack. Just install it with:
npm install --save-dev raw-loaderAnd add this portion to your webpack configuration:
And add this portion to your webpack configuration:
module: {
loaders: [
{
test: /\.stache$/,
loader: 'raw'
}
]
}
And with that, you can just use require() to load your mustache templates and use those with canjs like this:
var can = require('can');
var template = require('../templates/root.stache');
can.view.mustache('templateExample',template);
...
can.view('templateExample', data)
First require()
obviously just load’s can. Second require loads the actual template as a raw text into buffer. Then we need to register that template with ID that can then be used to render it with can.view
Final words
I’ve prepared a fully working “boiler-plate” that utilizes the examples given here. CanJS proportion of the code isn’t anything fancy so don’t treat it as example of good can app. Project is just there to highlight that you can use CanJS and build your project with webpack. Magic keywords for the project:
Grunt, Less, CanJS, Webpack & Mustache
Check it out here: https://github.com/rasjani/canjs_webpack
tags: CanJS - Webpack - javascript