In this appendix, you’ll learn how to set up a basic project structure with webpack, TypeScript, and Angular, a front-end framework by Google.[112] At the end, you’ll have a basis on which you can build a UI for your Node.js-powered applications.
If you’re reading this appendix, you’re probably already familiar with using Angular for front-end development. If not and you’d like to know more, I strongly recommend that you step through the Tour of Heroes tutorial on Angular’s website.[113] It contains a step-by-step guide that’ll introduce you to the relevant development concepts that are not covered here.
Setting up even a bare-bones Angular application takes a perhaps-surprising amount of boilerplate. Angular recommends using its quickstart for developing locally.[114] While this is a fast way to get started using Angular, the quickstart doesn’t address how to tie Angular into a webpack project.
In the code downloads that accompany this book, you’ll find a directory called extra. Inside it, there’s a subdirectory named angular-webpack that contains a very simple Angular project that builds with webpack.
Like other webpack projects in this book, the angular-webpack project runs with webpack-dev-server through npm. You can start it up and take a look if you’re interested in poking around.
The following is the simplest Angular project I could come up with that builds with webpack. You can use it as a reference implementation to compare against, or as a skeleton project rather than setting everything up yourself.
| | $ cd angular-webpack |
| | $ npm start |
| | |
| | > angular-webpack@1.0.0 start ./extra/angular-webpack |
| | > webpack-dev-server |
| | |
| | Project is running at http://localhost:61100/ |
| | webpack output is served from / |
| | Content not from webpack is served from ./extra/angular-webpack/dist |
| | ts-loader: Using typescript@2.3.2 and ./extra/angular-webpack/tsconfig.json |
| | Hash: 976f663472a8a9ae69c7 |
| | Version: webpack 2.4.1 |
Let’s start with an overview of the directory structure of an angular-webpack project.
| | $ tree -I node_modules --dirsfirst |
| | . |
| | ├── src |
| | │ ├── app |
| | │ │ ├── app.component.html |
| | │ │ ├── app.component.ts |
| | │ │ └── app.module.ts |
| | │ ├── index.html |
| | │ ├── main.ts |
| | │ ├── polyfills.ts |
| | │ └── vendor.ts |
| | ├── package.json |
| | ├── package-lock.json |
| | ├── tsconfig.json |
| | └── webpack.config.js |
Angular recommends following the convention that source code files go under the src directory, as you see here. Top-level files are generally configuration files.
The three ts files in the src directory are the entry points for webpack. Rather than cram all of the application’s JavaScript and CSS into a single bundle.js file, Angular recommends splitting it up.[115]
Here’s a brief overview of each of the top-level files in src, and how they contribute to the overall application:
index.html—This is used as a base template for HtmlWebpackPlugin to load the main application component. It contains a <my-app> to bootstrap the rest of the application.
main.ts—This file is the entry point for the main front-end code.
polyfills.ts—Angular takes advantage of the very latest browser features. Browsers don’t always support these features, so polyfills.ts loads up the relevant polyfill implementations.
vendor.ts—This file brings together the underlying framework and library code that your application depends on, such as Angular and Bootstrap.
The custom code for your application lives in src/app. Here’s a short description of each of those files.
app.module.ts—Defines your AppModule class using the @NgModule decorator. This class pulls all of the Angular bits together, such as your router and components.
app.component.ts—Exports the AppComponent class using the @Component decorator. This implements your main application’s <my-app> tag.
app.component.html—Template HTML content for AppComponent.
Like webpack, Angular makes aggressive use of npm peer dependencies. As a result, it takes quite a few packages to put together an Angular project. Here are the packages you’ll need for Angular:
The packages beginning with @angular are part of the Angular project proper. The rest are a combination of peer dependencies that Angular needs, and TypeScript typings that permit Angular to build under webpack.
Speaking of webpack, here’s the stack of dependencies you’ll need for it:
The angular2-template-loader is a webpack plugin that handles tying together Angular components that have external HTML template files, like the app.component.ts and app.component.html we discussed earlier. The other packages in this list are discussed in detail in Chapter 8, Creating a Beautiful User Experience.
Although much of the configuration in tsconfig.json and webpack.config.js is the same with and without Angular, there are a few differences. First, let’s look at the differences in tsconfig.json.
| | { |
| | "compilerOptions": { |
| | "outDir": "./dist/", |
| | "sourceMap": true, |
| | "module": "CommonJS", |
| | "target": "ES5", |
| | "allowJs": true, |
| | "alwaysStrict": true, |
| » | "lib": ["ES2016", "DOM"], |
| » | "experimentalDecorators": true, |
| » | "types": [ "node" ], |
| » | "typeRoots": [ "../node_modules/@types" ] |
| | } |
| | } |
The lib options need to contain ES2016 for Angular to work, since it relies on some recent JavaScript additions such as the Map. Polyfills are added for missing features, but TypeScript needs to know that those signatures are OK.
experimentalDecorators enable the @NgModule, @Component, and other decorators that Angular depends on. Without this flag, you’ll get TypeSript compilation errors.
Lastly, types and typeRoots are needed for handling the require method. Although dependencies can usually be brought in with the import keyword, sometimes require is needed to pull in dependencies dynamically. src/polyfills.ts contains an example of this.
Turning our attention to the webpack.config.js file, there are two changes worth noting. First is the way that ts files are handled. Here’s the rule:
| | rules: [{ |
| | test: /\.ts$/, |
| | use: [ 'ts-loader', 'angular2-template-loader' ], |
| | },{ |
The angular2-template-loader needs to be last in the list of ts rules. This means that component templates (specified in the @Component decorator’s templateUrl property) will be included properly.
The other change is the addition of a plugin to the plugins array:
| | new webpack.ContextReplacementPlugin( |
| | /angular(\\|\/)core(\\|\/)@angular/, |
| | path.resolve(__dirname, '../src') |
| | ), |
webpack.ContextReplacementPlugin provides a means for you to tell webpack how to resolve the locations of dynamically determined source files. Without this plugin, webpack will overestimate the packages it needs to support Angular. This keeps it to the required minimum dependencies when bundling.
Feel free to poke around the angular-webpack skeleton project. If you use the tips in this appendix, you should be able to use Angular for the front end of your own Node.js projects.