Angular + TypeScript + GruntTS
This seed project only includes the code responsible for building the app.js resource for the front-end, and requires some way to serve the resource (when you no longer want to open the file locally).
Angular is great because it makes unit testing easier. It is good to write tests when you want your code to stand the test of time.
TypeScript goes a step further by providing you with free (and optional) unit-tests that verify you aren't calling code that couldn't possibly work. It does so by providing type annotations. Strongly typed code also helps your IDE (such as WebStorm or IntelliJ IDEA) to provide offline documentation about the method you want to call or the model you want to construct, and tell you when you are missing semi-colons ;)
You might want to watch to also watch this inspirational video on getting setup.
Next you need to install the Grunt CLI plugin for creating Grunt projects.
$ npm install -g grunt-cli
For web modules, we are going to use Bower
$ npm install -g bower
Now we can install all the node and bower modules we need for our project
$ cd path/to/angular-ts-seed $ npm install $ bower install
Finally we can compile our project and run the tests
# the next line will move all the library code from bower_modules into a publicly accessible place # as well as compile the code and generate typescript modules from our HTML partials $ grunt init # now we should run all our unit tests to verify the build $ grunt test
At this point the terminal will appear to be locked up. It's not. It's just waiting for you to make code changes so that it can continuously compile whenever you make a change to the TypeScript source code. You can kill it at any time and rerun it without breaking anything.
When you want to run the actual project, you will need something to serve your public assets and API endpoints, and then run the grunt work task.
$ grunt work
Again, the task will watch your source files for changes and recompile as you go.
To view the file now, you can just open index.html in your browser to view your seed application.
About the Code
This project makes no prescription about which HTTP Server to use (despite the Play! icon :P). You can plug this into any web platform of your choice. The code hints at a strategy of driving the application through events by default, rather than round-trips to the database as the default. This is a good performance strategy, but not a requirement of this design.
The build tasks are structured to build code for 3 different use cases:
- Running and writing test code in a continuous compile setting
- Working on the App code in a continuous compile setting
- Deploying your app for production (left as an exercise for the reader, since this will depend on your needs)
When you need to add a library, you just need to do the following:
Find it on Bower Components
Add it to your dependencies:
$ bower install --save moar-jquery
Then copy the vendor js into your public/lib directory:
$ grunt bower
Grab the TypeScript definition file from DefinitelyTyped.
You will need to drop this definition file in your defs directory
This is a bit of a manual process currently, but there is an awesome project that may help to manage these files as well, called tsd
Add the definition file to your reference file
If you can't find your library on DefinitelyTyped, you can stub out your own definition file using the declare syntax to define variables and types that will be in scope when your application is running.
Even better, you should give these back to the community by adding it to the DefinitelyTyped repo.
This project is structured to harness TypeScript's reference file system, so that you can have models classes and other interfaces at the root level. This works really well when you have a library like Angular that provides you a module system for dependency injection, where you refer to the dependent objects from arguments of a function.
TypeScript's compiler will concatenate the files in the order of their dependencies (via the
We can simplify this by creating a single
reference.ts file with all the files referenced in the order that
If you are working within Angular on the same app, you don't really need to use CommonJS or RequireJS as you can just concatenate all your code into a single file (which is a good practice anyhow) and save on the module load time. TypeScript also has a way to make external modules if you need to load them asynchronously. You can convert your app into an AMD module, you can use the GruntTS plugin to generate an AMD loader as well as the definition file. Then when you want to share code between different modules, you would specify separate GruntTS tasks and add the separate code base's definition file to the dependent project's reference file. The dependent project's task will kick off the build of the project it depends on, so that you can now import the AMD module in your TypeScript code with the type signature generated from all the public code in your AngularTS project.
There are other benefits to using file concatenation, such as implicit Angular wiring using modules. Checkout this great introductory video that explains the Angular + GruntTS workflow.
To get coding, just run the following command:
$ grunt work-and-watch
This will watch your filesystem for changes and perform the following tasks:
Generate references in your reference file for any new files you create
Compile your templates into a TypeScript template module that you can refer to without having to make a separate request to the server.
Compile and concatenate all your TypeScript code into a single app.js file in your public JS directory
This will give you immediate feedback when a change you make will break some other piece of code (which may be annoying), so you can just run this process a single time by running:
$ grunt compile-work
Some times you will have old code laying around that may appear to be broken and you will get non-obvious failures where all you really need to do is recompile. So the recommended command for starting work on a project (after running all the tests as described below), is to run:
$ grunt work
To test your application, we concatenate your test code with the rest of your normal code and spin up a PhantomJS browser to run through all the concatenated test code. You can add src file dependencies (such as your external libraries) to the Gruntfile.coffee
You can open any browser to the test HTML file to drop debugger statements or break points in your code. With a modern browser, you can place breakpoints in your typescript code as a source map will be made available to the browser.
Whenever you are writing services, filters, controllers, or directives, it is a good idea to verify that they work in a sandbox setting with automated unit tests. Especially if you want these things to stand the test of time!
A good strategy for test code is to first verify that you even have a use case for writing code. You do this by writing your test code first (alongside some shell of actual code so that you don't get compilation errors). To get started on the testing path, just fire up:
$ grunt test-and-watch
This will do everything that running
work-and-watch does for your App Code (as mentioned above), but for your
test code. Additionally, it will run your Jasmine unit test suite after every code change. If you need to save
battery, or you are tired of hearing a bell tell you that you are failing, you can compile your tests a
single time with:
$ grunt compile-test $ grunt run-test
These two tasks are run separately because running the tests could take a while, and maybe you just want to verify that the code compiles. Vice versa, maybe you don't want to recompile, but you want to drop a debugger in some code that was broken before. Splitting the tasks allows you to dig a little deeper on the run-time failure and compile-time failure of your test code without forcing them both on you.
For reasons mentioned above, you might have failures for test code files that are laying around because they have moved or something silly, where the best thing to do is to just remove that old code. Before writing any code after you have pulled code changes from upstream, I highly recommend that you clean your code, compile the test code, and run the tests. The following command will do just this:
$ grunt test
Additionally, it will put you in the
test-and-watch mode, since you should probably start with your test
code anyway :P You could pretty easily write a
clean-and-test task, but I'll leave that as an exercise
to the reader.
You should always test your code but sometimes all you need is a basic page with all the well-tested and trusty Angular built-in tools. In these cases, it will be pretty obvious, as you will probably be doing all your work in the HTML.
The only thing you need to verify at this point is that your users' experience is safe from breaking changes. This is where End-To-End (E2E) tests come in. Writing E2E tests will often involve using a Web Driver to click, swipe, and type its way through your website and expecting to see some feature work as you would expect it. Writing E2E tests helps take you off the hook when some other code (not YOUR code, of course) causes some feature to stop working as expected.
While there are no E2E tests in this example project, you can set them up to run as either a separate task or just have them run in Phantom with the rest of your test code.
This project is based off of the wonderful GruntTS plugin and Angular workflow ideas put forth by @basarat.
Also I highly recommend checking out the tsd project for managing your TypeScript definition files.