Angular2初探

Angular2是Google下一代MV*框架括丁,用于構(gòu)建復(fù)雜瀏覽器應(yīng)用。Angular2給WEB或移動Apps帶來了一攬子解決方案伶选,從模板渲染到數(shù)據(jù)綁定史飞,從Http服務(wù)到表單處理等等,總之仰税,你想要的构资,Angular2基本上都已封裝好了。
  萬事始于Hello World陨簇,不論Angular2怎么牛吐绵,咱們先得把官方的例子跑起來再說。這里使用基于webpack創(chuàng)建Angular應(yīng)用河绽。

環(huán)境準備
  node v5.x.x
  npm v3.x.x
step1:創(chuàng)建并配置本項目
創(chuàng)建項目目錄:

mkdir angular2Demo
cd angular2Demo

創(chuàng)建配置文件
典型的 Angular 項目需要一系列配置文件
package.json 用來標(biāo)記出本項目所需的 npm 依賴包拦赠。
tsconfig.json 定義了 TypeScript 編譯器如何從項目源文件生成 JavaScript 代碼。
typings.json 為那些 TypeScript 編譯器無法識別的庫提供了額外的定義文件葵姥。
webpack.config.js為構(gòu)建Angular應(yīng)用所進行的一系列webpack配置。


package.json

{
  "name": "angular2demo",
  "version": "1.0.0",
  "description": "Angular 2 demo.",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server --inline --progress --port 8080",
    "test": "karma start",
    "build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail",
    "postinstall": "typings install"
  },
  "dependencies": {
    "@angular/common": "2.0.0",
    "@angular/compiler": "2.0.0",
    "@angular/core": "2.0.0",
    "@angular/forms": "2.0.0",
    "@angular/http": "2.0.0",
    "@angular/platform-browser": "2.0.0",
    "@angular/platform-browser-dynamic": "2.0.0",
    "@angular/router": "3.0.0",
    "core-js": "^2.4.1",
    "rxjs": "5.0.0-beta.12",
    "zone.js": "^0.6.23"
  },
  "devDependencies": {
    "angular2-template-loader": "^0.4.0",
    "awesome-typescript-loader": "^2.2.4",
    "css-loader": "^0.23.1",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.5",
    "html-loader": "^0.4.3",
    "html-webpack-plugin": "^2.15.0",
    "jasmine-core": "^2.4.1",
    "karma": "^1.2.0",
    "karma-jasmine": "^1.0.2",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-webpack": "^1.8.0",
    "null-loader": "^0.1.1",
    "phantomjs-prebuilt": "^2.1.7",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.5.2",
    "style-loader": "^0.13.1",
    "typescript": "^2.0.2",
    "typings": "^1.3.2",
    "webpack": "^1.13.0",
    "webpack-dev-server": "^1.14.1",
    "webpack-merge": "^0.14.0"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/HalZhan/angular2Demo.git"
  },
  "author": "halzhan",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/HalZhan/angular2Demo/issues"
  },
  "homepage": "https://github.com/HalZhan/angular2Demo#readme"
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

typings.json

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160725163759",
    "jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
    "node": "registry:dt/node#6.0.0+20160909174046"
  }
}

webpack.config.js

module.exports = require('./config/webpack.dev.js'); // 待補充

karma.conf.js

module.exports = require('./config/karma.conf.js'); // 待補充

下面我們繼續(xù)完善配置文件句携。
公共配置
  我們可以為開發(fā)榔幸、產(chǎn)品和測試環(huán)境定義分別各自的配置文件。 但三者總會有一些公共配置矮嫉。 于是我們把那些公共的配置收集到一個名叫 webpack.common.js 的獨立文件中削咆。


config/webpack.common.js

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');

module.exports = {
  entry: {
    'polyfills': './src/polyfills.ts', // 運行Angular時所需的一些標(biāo)準js
    'vendor': './src/vendor.ts', // Angular、Lodash蠢笋、bootstrap.css......
    'app': './src/main.ts' // 應(yīng)用代碼
  },

  resolve: {
    extensions: ['', '.js', '.ts'] // 加載的文件類型(明確的擴展名拨齐、.js、.ts)
  },

  module: {
    loaders: [
      {
        test: /\.ts$/,
        loaders: ['awesome-typescript-loader',
                  'angular2-template-loader' // 用于加載 Angular 組件的模板和樣式
        ]
      }, // ts - 將typescript代碼轉(zhuǎn)譯成es5的加載器昨寞,由tsconfig.json文件指導(dǎo)
      {
        test: /\.html$/,
        loader: 'html' // 為組件模板準備的加載器
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'file?name=assets/[name].[hash].[ext]' // 圖片和字體文件也能被打包
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
      }, // 模式匹配應(yīng)用級樣式
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw'
      } // 模式匹配組件局部樣式 ( 在組件元數(shù)據(jù)的 styleUrls 屬性中指定的那些 ) 
    ]
  },

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: ['app', 'vendor', 'polyfills']
    }), // 提取公共代碼

    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }) // 自動向目標(biāo).html文件注入script和link標(biāo)簽
  ]
};

config/helpers.js

var path = require('path');
var _root = path.resolve(__dirname, '..');
function root(args) {
  args = Array.prototype.slice.call(arguments, 0);
  return path.join.apply(path, [_root].concat(args));
}
exports.root = root;

開發(fā)環(huán)境配置
config/webpack.dev.js

var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');

module.exports = webpackMerge(commonConfig, {
  devtool: 'cheap-module-eval-source-map',

  output: {
    path: helpers.root('dist'),
    publicPath: 'http://localhost:8080/',
    filename: '[name].js',
    chunkFilename: '[id].chunk.js'
  },

  plugins: [
    new ExtractTextPlugin('[name].css')
  ],

  devServer: {
    historyApiFallback: true,
    stats: 'minimal'
  }
});

產(chǎn)品環(huán)境配置
config/webpack.prod.js

var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');

const ENV = process.env.NODE_ENV = process.env.ENV = 'production';

module.exports = webpackMerge(commonConfig, {
  devtool: 'source-map',

  output: {
    path: helpers.root('dist'),
    publicPath: '/',
    filename: '[name].[hash].js',
    chunkFilename: '[id].[hash].chunk.js'
  },

  htmlLoader: {
    minimize: false // workaround for ng2
  },

  plugins: [
    new webpack.NoErrorsPlugin(), //  如果出現(xiàn)任何錯誤瞻惋,就終止構(gòu)建
    new webpack.optimize.DedupePlugin(), // 檢測完全相同 ( 以及幾乎完全相同 ) 的文件厦滤,并把它們從輸出中移除
    new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618
                                          // 最小化 (minify) 生成的包
      mangle: {
        keep_fnames: true
      }
    }),
    new ExtractTextPlugin('[name].[hash].css'), // 把內(nèi)嵌的 css 抽取成外部文件,并為其文件名添加“緩存無效哈霞呃牵”
    new webpack.DefinePlugin({ // 用來定義環(huán)境變量掏导,以便我們在自己的程序中引用它
      'process.env': {
        'ENV': JSON.stringify(ENV)
      }
    })
  ]
});

(可選)測試環(huán)境配置
config/webpack.test.js

var helpers = require('./helpers');

module.exports = {
  devtool: 'inline-source-map',

  resolve: {
    extensions: ['', '.ts', '.js']
  },

  module: {
    loaders: [
      {
        test: /\.ts$/,
        loaders: ['awesome-typescript-loader', 'angular2-template-loader']
      },
      {
        test: /\.html$/,
        loader: 'html'

      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'null'
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: 'null'
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw'
      }
    ]
  }
}

(可選)Karma單元測試配置
config/karma.conf.js

var webpackConfig = require('./webpack.test');

module.exports = function (config) {
  var _config = {
    basePath: '',

    frameworks: ['jasmine'],

    files: [
      {pattern: './config/karma-test-shim.js', watched: false}
    ],

    preprocessors: {
      './config/karma-test-shim.js': ['webpack', 'sourcemap']
    },

    webpack: webpackConfig,

    webpackMiddleware: {
      stats: 'errors-only'
    },

    webpackServer: {
      noInfo: true
    },

    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['PhantomJS'],
    singleRun: true
  };

  config.set(_config);
};

config/karma-test-shim.js
  告訴 Karma 哪些文件需要預(yù)加載,首要的是:帶有“測試版提供商”的 Angular 測試框架是每個應(yīng)用都希望預(yù)加載的羽峰。

Error.stackTraceLimit = Infinity;

require('core-js/es6');
require('core-js/es7/reflect');

require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');

var appContext = require.context('../src', true, /\.spec\.ts/);

appContext.keys().forEach(appContext);

var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');

testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());

step2:編寫源碼
src/index.html

<!DOCTYPE html>
<html>
  <head>
    <base href="/">
    <title>Angular With Webpack</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <my-app>Loading...</my-app>
  </body>
</html>

src/main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app/app.module';
if (process.env.ENV === 'production') {
  enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);

public/css/styles.css

body {
    background: #0147A7;
    color: #fff;
}

src/app/app.component.ts

import { Component } from '@angular/core';
import '../../public/css/styles.css';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent { }

src/app/app.component.html
這里需要用到Angular Logo趟咆,下載后放入"public/images/"目錄下。

<main>
  <h1>Hello from Angular App with Webpack</h1>
  <img src="../../public/images/angular.png">
</main>

src/app/app.component.css

main {
  padding: 1em;
  font-family: Arial, Helvetica, sans-serif;
  text-align: center;
  margin-top: 50px;
  display: block;
}

(用于單元測試梅屉,可選)src/app/app.component.spec.ts

import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('App', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({ declarations: [AppComponent]});
  });
  it ('should work', () => {
    let fixture = TestBed.createComponent(AppComponent);
    expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent');
  });
});

src/app/app.module.ts

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

src/vendor.ts

// Angular
import '@angular/platform-browser';
import '@angular/platform-browser-dynamic';
import '@angular/core';
import '@angular/common';
import '@angular/http';
import '@angular/router';
// RxJS
import 'rxjs';
// Other vendors for example jQuery, Lodash or Bootstrap
// You can import js, ts, css, sass, ...

src/polyfills.ts

import 'core-js/es6';
import 'core-js/es7/reflect';
require('zone.js/dist/zone');
if (process.env.ENV === 'production') {
  // Production
} else {
  // Development
  Error['stackTraceLimit'] = Infinity;
  require('zone.js/dist/long-stack-trace-zone');
}

step3:編譯運行

  1. 在項目根目錄下值纱,執(zhí)行
webpack --progress --colors

(--progress --colors是為了查看進度,可以不用加)

  1. 全局安裝webpack-dev-server
npm install -g webpack-dev-server --verbose

(--verbose可以顯示安裝詳細信息坯汤,可以不用加上)

  1. 啟動webpack server
webpack-dev-server --content-base dist/

(設(shè)置靜態(tài)文件訪問路徑)

step4:查看結(jié)果
訪問localhost:8080虐唠,如果一切順利,我們能夠看到最終的結(jié)果:

angular2-start.png

Bingo !


樣例源碼已托管至github玫霎,如有興趣可自行clone

git clone https://github.com/HalZhan/angular2Demo.git
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凿滤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子庶近,更是在濱河造成了極大的恐慌翁脆,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鼻种,死亡現(xiàn)場離奇詭異反番,居然都是意外死亡,警方通過查閱死者的電腦和手機叉钥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門罢缸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人投队,你說我怎么就攤上這事枫疆。” “怎么了敷鸦?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵息楔,是天一觀的道長。 經(jīng)常有香客問我扒披,道長值依,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任碟案,我火速辦了婚禮愿险,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘价说。我一直安慰自己辆亏,他們只是感情好风秤,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著褒链,像睡著了一般唁情。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甫匹,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天甸鸟,我揣著相機與錄音,去河邊找鬼兵迅。 笑死抢韭,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的恍箭。 我是一名探鬼主播刻恭,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扯夭!你這毒婦竟也來了鳍贾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤交洗,失蹤者是張志新(化名)和其女友劉穎骑科,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體构拳,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡咆爽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了置森。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斗埂。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凫海,靈堂內(nèi)的尸體忽然破棺而出呛凶,到底是詐尸還是另有隱情,我是刑警寧澤行贪,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布把兔,位于F島的核電站,受9級特大地震影響瓮顽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜围橡,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一暖混、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧翁授,春花似錦拣播、人聲如沸晾咪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谍倦。三九已至,卻和暖如春泪勒,著一層夾襖步出監(jiān)牢的瞬間昼蛀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工圆存, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叼旋,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓沦辙,卻偏偏與公主長得像夫植,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子油讯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容