Now that CodeKit 3 has launched it’s time to dig into some new functionality it provides; One of my favorites being, the ability for CodeKit to now track ES Module imports in your JavaScript and TypeScript files! This means we now have a true path on bundling up our JavaScript files without hooks.

While some will want a more flushed out experience via Browserify or Rollup bundling, using TypeScript isn’t that bad, especially when you’re really only using one .ts to do the bundling while the rest of your code can be pure JavaScript.

The file structure

1
2
3
4
5
6
7
8
js/
nested/
maths.js
bundle.js
bundle.ts <-- the files that provides bundling
onload.js
text.js
index.html

From the above example you’ll see one TypeScript file bundle.ts and its sole purpose is to import our top level JavaScript files and bundle them up into bundle.js. The reason for TypeScript is because it provides built-in bundling so long as you select either the AMD or System format, in this example we’ll be using the System format.

The contents of each file:

bundle.ts
1
import './onload';

Yep, just one line, as onload.js is the top-level file in this project, you will most likely have more.

onload.js
1
2
3
4
5
6
7
8
9
import {upper, title} from './text';
import {add, increment} from './nested/maths';
console.log( upper('yell a message here.') );
console.log( title('title case message here.') );
console.log(`2 + 3 = ${add( 2, 3 )}`);
console.log(`increment 4 by 1 = ${increment( 4 )}`);
console.log(`increment 4 by 3 = ${increment( 4, 3 )}`);

You can see here that onload.js loads in our other two files and uses them to log their output to the console.

text.js
1
2
3
4
5
6
export const upper = (text='') => text.toUpperCase();
export const title = (text='') => text
.toLowerCase()
.split(' ')
.map( s => `${s[0].toUpperCase()}${s.slice(1)}`)
.join(' ');
nested/maths.js
1
2
export const add = ( a, b ) => a + b;
export const increment = ( value, by=1 ) => value + by;

So, with all of the above coded imported into onload.js and it being imported by bundle.ts anytime you save any one of those files CodeKit is now smart enough to build your new bundle.js which will produce ES 5 code in the System format.

Here you can see CodeKit showing you what files are linked.

bundle.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
System.register("text", [], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var upper, title;
return {
setters:[],
execute: function() {
exports_1("upper", upper = function (text) {
if (text === void 0) { text = ''; }
return text.toUpperCase();
});
exports_1("title", title = function (text) {
if (text === void 0) { text = ''; }
return text
.toLowerCase()
.split(' ')
.map(function (s) { return ("" + s[0].toUpperCase() + s.slice(1)); })
.join(' ');
});
}
}
});
System.register("nested/maths", [], function(exports_2, context_2) {
"use strict";
var __moduleName = context_2 && context_2.id;
var add, increment;
return {
setters:[],
execute: function() {
exports_2("add", add = function (a, b) { return a + b; });
exports_2("increment", increment = function (value, by) {
if (by === void 0) { by = 1; }
return value + by;
});
}
}
});
System.register("onload", ["text", "nested/maths"], function(exports_3, context_3) {
"use strict";
var __moduleName = context_3 && context_3.id;
var text_1, maths_1;
return {
setters:[
function (text_1_1) {
text_1 = text_1_1;
},
function (maths_1_1) {
maths_1 = maths_1_1;
}],
execute: function() {
console.log(text_1.upper('yell a message here.'));
console.log(text_1.title('title case message here.'));
console.log("2 + 3 = " + maths_1.add(2, 3));
console.log("increment 4 by 1 = " + maths_1.increment(4));
console.log("increment 4 by 3 = " + maths_1.increment(4, 3));
}
}
});
System.register("bundle", ["onload"], function(exports_4, context_4) {
"use strict";
var __moduleName = context_4 && context_4.id;
return {
setters:[
function (_1) {}],
execute: function() {
}
}
});

Now that we have our code bundled up via the System module format there’s one final step. As you can see above it’s using a global called System which “registers” each file into its own scope and passes in its dependencies. Because of this, we’ll need to load in part of the SystemJS library, I say part because we only need the “register” portion of it which we can grab from a CDN or load it locally.

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head><title></title></head>
<body>
<script
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.40/system-register-only.js">
</script>
<script
type="text/javascript"
src="js/bundle.js"
onload="System.import('bundle')">
</script>
</body>
</html>

When we load in our bundle.js files we need to set the onload event to tell SystemJS to import our bundled up code so that it get executed.

Setting up CodeKit file options

We’ve gone over each role of the files provided but we need to adjust CodeKit slightly for all of this to work correctly.

If you enjoy this work flow you’ll probably want to edit CodeKits “project defaults” instead of doing this for every single new file or project.

TypeScript settings

We’ll want

  • Output Module Type System
  • ECMAScript Target Version ES5
  • When This File Changes Or Builes Compile it

JavaScript settings (only if you want to lint it, otherwise set it to ignore)

  • Check Syntax With ESLint
  • Transpile With Nothing
  • When This File Changes Or Builes Process it
  • To This Path The exact path to the JavaScript file you’re processing

ESLint settings

  • Source Type Module
  • Environments Check “ES6”

Github sample project

The code you see above is on Github with a CodeKit config file, I hope this helps folks that are looking for a way to write in the new ES syntax as well as start using ES Module imports to bundle up their code.

Happy coding!