Skip to content

[投稿]从零开始构建一个完整的Angular应用 #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
9 changes: 9 additions & 0 deletions src/app/_shared/api/articles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import {Article} from '../../models/article';
import {Observable} from 'rxjs/Observable';

const items: Article[] = [
{
id: 'indooorsman_angular-from-zero-00',
title: 'Angular 2从零开始系列 - 00',
summary: '从零开始构建一个完整的Angular应用',
content: require('./indooorsman/angular-from-zero-00/index.md'),
first: true,
tags: ['Angular', 'Webpack'],
authors: ['indooorsman'],
},
{
id: '使用 Angular 2 制作简单的 Accordion 组件 - Template Driven',
title: '使用 Angular 2 制作简单的 Accordion 组件 - Template Driven',
Expand Down
294 changes: 294 additions & 0 deletions src/app/_shared/api/articles/indooorsman/angular-from-zero-00/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
# Angular 2从零开始系列 - 00

本系列将会从零开始构建一个完整的Angular项目,最终实现一个简易版的twitter,不依赖任何seed或starter,也不使用Angular cli,这样做的目的是让自己对Angular应用开发的每一个环节都有一定的了解
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AngularTwitter 项目包含后端吗?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

包含,后面会做服务端渲染
目前的代码还没有包含,我是一遍写教程,一遍写示例代码 :p

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果包含后端,能否在 line5 “特性” 部分添加后端内容,并且在 line74 “目录结构”中预留后端文件夹?

Copy link
Contributor Author

@indooorsman indooorsman Feb 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

特性部分写了服务端渲染,具体怎么实现我其实还没想好。另外我的想法是一步一步实现各个特性,而不是一开始就提供一个完整的脚手架,这样读者可能更容易接受吧。。。也有身临其境的感觉,嘿嘿

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

所以服务端相关的东西,可能会在最后期才会添加到“目录结构”中

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

收到。


最终的示例会包含以下特性:

- 采用`webpack`进行构建、编译、模块打包
- 模板采用`pug`编写,并支持分环境配置全局模板变量
- 样式采用`less`编写,并支持分环境配置全局less变量
- 路由懒加载
- 通过`npm script`『一键』创建组件相关目录和文件
- 模块热替换(hot module replacement)
- 多国语言支持
- 动态加载组件
- AoT编译
- 服务端渲染

希望对大家能有所帮助

 

___序章___

## 基础知识

- NPM <https://www.npmjs.com>
- ES6 <http://es6.ruanyifeng.com>
- Webpack <https://webpack.js.org>
- Angular <https://angular.cn>

以上内容是我认为在开始动手之前必须要有一定了解的,不必精通,浏览一遍各自的文档,理解其核心概念即可

那么这里为什么没有提`TypeScript`呢?因为根据我的实践经验,有`ES6`的基础的话,不必系统学习`TypeScript`,开发中遇到其特有的功能时进行针对性的查阅就行了

## 创建项目

### 环境

我们采用`npm`来管理依赖,`NodeJS`运行环境当然是必不可少的,所以第一步就是安装`NodeJS` <https://nodejs.org/>

另外介于国内的网络环境,推荐使用淘宝的npm镜像:<https://npm.taobao.org/>,请按照网站上的说明进行配置

### 初始化

- 打开终端(Windows用户建议使用[git-bash](https://git-scm.com/downloads)):

```bash
mkdir angular-twitter
cd angular-twitter
npm init #可按照提示填写项目基本信息,或直接一路回车
```

- 安装依赖:

```bash
# Angular
npm install @angular/common @angular/compiler @angular/compiler-cli @angular/core @angular/forms @angular/http @angular/platform-browser @angular/platform-browser-dynamic @angular/platform-server @angular/router rxjs zone.js core-js --save

# Webpack
npm install webpack --save-dev

# TypeScript
npm install typescript --save-dev

# TypeScript loader for webpack
npm install awesome-typescript-loader --save-dev
```

注意这些并不是最终全部的依赖,随着开发的进展,后面会陆续添加其他依赖

- 目录结构:

```text
anuglar-twitter/
├── src/
├── app/
├── index.html
├── tsconfig.json
├── webpack.config.js
├── package.json
```
其中:
- `src`目录存放我们的ts及模板等源文件
- `./webpack.config.js`是webpack的配置文件
- `./package.json`是最开始执行`npm init`之后生成的
- `./src/tsconfig.json`是typescript的配置文件
- `./src/index.html`是主页面
- `./src/app`则是我们app的具体代码喽

### Hello world!

接下来我们先实现一个hello world,首先创建app的入口模块及根组件(假设你已经阅读了Angular官方的快速起步和开发指南,没有的话请移步<https://angular.cn>),在`./src/app/`目录下创建如下文件:

|文件名|说明|
|---|---|
|app.module.ts|入口模块|
|app.component.ts|根组件|
|app.template.html|根组件模板|
|app.styles.css|根组件样式|

```js
//app.module.ts

import {NgModule} from "@angular/core";
import {AngularTwitterAppComponent} from "./app.component";
import {BrowserModule} from "@angular/platform-browser";
@NgModule({
imports: [
BrowserModule
],
declarations: [
AngularTwitterAppComponent
],
providers: [],
bootstrap: [AngularTwitterAppComponent]
})
export class AppModule {

}
```
```js
//app.component.ts

import {Component} from "@angular/core";
@Component({
selector: 'angular-twitter-app',
templateUrl: './app.template.html',
styleUrls: ['./app.styles.css']
})
export class AngularTwitterAppComponent {

}
```
```html
<!-- app.template.html -->
<h1>Hello World !</h1>
```
```css
/* app.styles.css */
h1 {
font-weight: normal;
}
```

然后在`./src`创建app的启动文件`main.ts`
```js
import 'core-js'; // es6+es7 polyfills
import 'zone.js/dist/zone.js'; // Angular所依赖的zone.js,必须在core-js之后加载

import {AppModule} from "./app/app.module";
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";
platformBrowserDynamic().bootstrapModule(AppModule);
```

修改`./src/tsconfig.json`
```json
{
"compilerOptions": {
"target": "es5",
"module": "es6",
"experimentalDecorators": true,
"moduleResolution": "node",
"lib": [
"dom",
"es6"
],
"typeRoots": [
"../node_modules/@types"
],
"types": [
"node"
]
}
}
```
`tsconfig.json`中各个字段的说明:

|字段名|值|说明|
|---|---|------|
|target|es5|编译目标,将ts文件编译成符合es5规范的js代码|
|module|es6|编译目标采用es6的模块管理方式,目的是能够利用webpack和es6模块导入的特性来做tree-shaking|
|experimentalDecorators|true|使用实验性的装饰器,这个是必须的设置,因为Angular的源码中使用了它|
|moduleResolution|node|由于我们使用了node的包管理工具npm来下载依赖,所以这里也是必须的设置,<br>否则在ts中导入node_modules目录下的模块时,ts编译器会找不到它|
|lib|["dom","es6"]|同样是必须的设置,否则用到es6的地方编译会报错|
|typeRoots|["../node_modules/@types"]|参考<br><https://www.tslang.cn/docs/handbook/tsconfig-json.html#types-typeroots-and-types>|
|types|["node"]|为`require`等方法提供类型支持,需要先安装`@types/node`<br>(在项目根目录下执行`npm install @types/node --save`)

&nbsp;

修改`webpack.config.js`:
```js
module.exports = {
entry: {
'app': './src/main.ts' //入口文件
},

output: {
path: './src', //生成打包文件的目录
filename: '[name].bundle.js' //打包文件的名字,本例中将是`app.bundle.js`
},

resolve: {
extensions: ['.js', '.ts'] //这样配置在import的时候,就可以省略.js和.ts的后缀了
},

module: {
rules: [
{
test: /\.ts$/,
use: [
{
loader: 'awesome-typescript-loader', //编译ts的loader
options: {
configFileName: './src/tsconfig.json' //配置tsconfig.json的路径
}
},
'angular2-template-loader'
// angular2-template-loader会把Angular组件中的templateUrl和styleUrls替换成template和styles,
// 并添加require,参考<https://github.com/TheLarkInn/angular2-template-loader>
// 当然需要先安装它:在项目根目录下执行`npm install angular2-template-loader --save-dev`
]
},
{
test: /\.(css|html|htm)$/,
use: 'raw-loader'
// 对于css、html、htm直接取得其文本内容,在之后的文章里会分别替换成less和pug
// 在项目根目录下执行`npm install raw-loader --save-dev`
}
]
}
};
```

修改`./src/index.html`:
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Angular Twitter Demo</title>
</head>
<body>
<angular-twitter-app>Loading...</angular-twitter-app>
<!--注意下面引用的是webpack打包生成的文件-->
<script type="text/javascript" src="app.bundle.js"></script>
</body>
</html>
```

最后,我们通过npm scripts来写一段脚本执行打包和启动一个静态服务器(更多关于npm scripts的信息请参考<https://docs.npmjs.com/files/package.json>以及<https://docs.npmjs.com/misc/scripts>)

修改`./package.json`:
```json
{
"name": "angular-twitter",
...
"scripts": {
"webpack": "webpack --config ./webpack.config.js --bail --progress",
"server": "static-server ./src",
"start": "npm run webpack && npm run server"
},
...
}
```
其中`scripts.webpack`中的命令参数说明:

|参数|说明|
|---|---|
|--config|指定配置文件路径|
|--bail|当打包时遇到第一个错误就立刻中断打包|
|--progress|显示打包进度|

更多的参数说明请参考<https://webpack.js.org/api/cli/>

`scripts.server`中用到了一个新的node模块`static-server`,所以我们需要在项目根目录下执行`npm install static-server --save-dev`

好啦!现在我们可以在项目根目录下执行`npm start`来试试看了!

执行`npm start`之后若看到如下的提示,就说明已经打包成功并且启动了静态服务:
```bash
* Static server successfully started.
* Serving files at: http://localhost:9080
* Press Ctrl+C to shutdown.
```

现在用浏览器打开`http://localhost:9080`:

![screenshot1](../assets/screenshot1.png)

序章到此就结束了,下一章将引入`pug`和`less`,以及通过`webpack`的`file-loader`来处理模板和样式中对图片等静态资源的引用。

示例源码:<https://github.com/indooorsman/angular-twitter/tree/helloWorld>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.