Angular2初探

作者: 风起云涌Hal | 来源:发表于2016-10-04 18:19 被阅读3136次

    Angular2是Google下一代MV*框架,用于构建复杂浏览器应用。Angular2给WEB或移动Apps带来了一揽子解决方案,从模板渲染到数据绑定,从Http服务到表单处理等等,总之,你想要的,Angular2基本上都已封装好了。
      万事始于Hello World,不论Angular2怎么牛,咱们先得把官方的例子跑起来再说。这里使用基于webpack创建Angular应用。

    环境准备
      node v5.x.x
      npm v3.x.x
    step1:创建并配置本项目
    创建项目目录:

    mkdir angular2Demo
    cd angular2Demo
    

    创建配置文件
    典型的 Angular 项目需要一系列配置文件
    package.json 用来标记出本项目所需的 npm 依赖包。
    tsconfig.json 定义了 TypeScript 编译器如何从项目源文件生成 JavaScript 代码。
    typings.json 为那些 TypeScript 编译器无法识别的库提供了额外的定义文件。
    webpack.config.js为构建Angular应用所进行的一系列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'); // 待补充
    

    下面我们继续完善配置文件。
    公共配置
      我们可以为开发、产品和测试环境定义分别各自的配置文件。 但三者总会有一些公共配置。 于是我们把那些公共的配置收集到一个名叫 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时所需的一些标准js
        'vendor': './src/vendor.ts', // Angular、Lodash、bootstrap.css......
        'app': './src/main.ts' // 应用代码
      },
    
      resolve: {
        extensions: ['', '.js', '.ts'] // 加载的文件类型(明确的扩展名、.js、.ts)
      },
    
      module: {
        loaders: [
          {
            test: /\.ts$/,
            loaders: ['awesome-typescript-loader',
                      'angular2-template-loader' // 用于加载 Angular 组件的模板和样式
            ]
          }, // ts - 将typescript代码转译成es5的加载器,由tsconfig.json文件指导
          {
            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')
          }, // 模式匹配应用级样式
          {
            test: /\.css$/,
            include: helpers.root('src', 'app'),
            loader: 'raw'
          } // 模式匹配组件局部样式 ( 在组件元数据的 styleUrls 属性中指定的那些 ) 
        ]
      },
    
      plugins: [
        new webpack.optimize.CommonsChunkPlugin({
          name: ['app', 'vendor', 'polyfills']
        }), // 提取公共代码
    
        new HtmlWebpackPlugin({
          template: 'src/index.html'
        }) // 自动向目标.html文件注入script和link标签
      ]
    };
    

    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;
    

    开发环境配置
    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'
      }
    });
    

    产品环境配置
    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(), //  如果出现任何错误,就终止构建
        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'), // 把内嵌的 css 抽取成外部文件,并为其文件名添加“缓存无效哈希”
        new webpack.DefinePlugin({ // 用来定义环境变量,以便我们在自己的程序中引用它
          'process.env': {
            'ENV': JSON.stringify(ENV)
          }
        })
      ]
    });
    

    (可选)测试环境配置
    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 哪些文件需要预加载,首要的是:带有“测试版提供商”的 Angular 测试框架是每个应用都希望预加载的。

    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. 在项目根目录下,执行
    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/
    

    (设置静态文件访问路径)

    step4:查看结果
    访问localhost:8080,如果一切顺利,我们能够看到最终的结果:

    angular2-start.png

    Bingo !


    样例源码已托管至github,如有兴趣可自行clone

    git clone https://github.com/HalZhan/angular2Demo.git
    

    相关文章

      网友评论

      • 9e1804224d7a:你好,请问你这个demo,自己跑起来过么?我按照你这个demo,npm install 完毕后,执行$ webpack的时候,报很多错误!能帮我看下么??
        风起云涌Hal:@9e1804224d7a 是些什么错误?
      • 苏三书:看了下官网的quick start已经有点晕了,当初用过angular1.x也没什么卵用 :sob:
        风起云涌Hal:模块化,数据绑定等等,都是非常有用的,得多看看官方文档,辅助做些小demo,对前端技术的成长会大有裨益的。
      • NANAphei:大神您好,我是电子社编辑安娜,咱们约本书吧 我的微信80303489 :smiley:
        风起云涌Hal:@NANAphei :pray: 很荣幸啊,不过为啥微信搜不到你呢?
      • wblearn:坐等Angular2进阶 :smile:
        风起云涌Hal:@wblearn 坐等:smiley:
      • 晗笑书生:没有家手脚 工具吗?
        风起云涌Hal:@jun_dev 官方出了,不过基于webpack构建的倒是没有。
      • 吃饭用盘装:一个hello world需要这么多配置,可见入门门槛异常高
        风起云涌Hal:@不搞艺术的程序员 这些配置不单单是写个hello world,同样也可以构建大型应用。
      • 小明我爱你:漂亮
        小明我爱你:@风起云涌Hal :stuck_out_tongue_winking_eye:
        风起云涌Hal:@小明我爱你 :smiley: 小明?
      • 006c3a9a9439:大牛
        风起云涌Hal:@Brian82 不敢当,学习并记录一下。

      本文标题:Angular2初探

      本文链接:https://www.haomeiwen.com/subject/hxljyttx.html