Spec-Zone.ru › Angular 2

Webpack: введение

Создавайте приложения Angular с помощью инструментов на основе Webpack.

Webpack — популярный модульный сборщик, инструмент для объединения исходного кода приложения в удобные части и для загрузки этого кода с сервера в браузер.

Это отличная альтернатива подходу SystemJS, используемому в других разделах документации. Это руководство предоставляет представление о Webpack и объясняет, как использовать его с приложениями Angular.

Содержание

  • Что такое Webpack?
    • Входные и выходные данные
    • Несколько пакетов
    • Загрузчики
    • Плагины
  • Настройка Webpack
    • Полифилы
    • Общая настройка
    • Внутри webpack.common.js
      • entry
      • Разрешение импорта без расширений
      • module.rules
      • Плагины
      • CommonsChunkPlugin
      • HtmlWebpackPlugin
    • Настройка для конкретной среды
    • Настройка для разработки
    • Настройка для производства
    • Настройка для тестирования
  • Попробовать
  • Основные моменты
  • Заключение

Вы также можете скачать окончательный результат.

Что такое Webpack?

Webpack — мощный модульный сборщик. Пакет — это файл JavaScript, который включает активы, которые принадлежат вместе и должны быть отправлены клиенту в ответе на запрос одного файла. Пакет может включать JavaScript, CSS-стили, HTML и почти любой другой тип файла.

Webpack обходит ваш исходный код приложения, ищет import операторы, строит граф зависимостей и генерирует один или несколько пакетов. С помощью плагинов и правил Webpack может предварительно обрабатывать и минимизировать различные файлы, не являющиеся JavaScript, такие как файлы TypeScript, SASS и LESS.

Вы определяете, что делает Webpack и как он это делает, с помощью файла конфигурации JavaScript, webpack.config.js.

Входные и выходные данные

Вы предоставляете Webpack один или несколько файлов входных точек и позволяете ему найти и включить зависимости, исходящие из этих точек. Единственным файлом точки входа в этом примере является основной файл приложения src/main.ts:

webpack.config.js (одиночный вход)

entry: {
  'app': './src/main.ts'
},

Webpack проверяет этот файл и рекурсивно проходит по import зависимостям.

src/main.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent { }

Он видит, что вы импортируете @angular/core, поэтому добавляет его в свой список зависимостей для потенциального включения в пакет. Он открывает файл @angular/core и следует за его сетью import операторов, пока не построит полную зависимость граф от main.ts вниз.

Затем он выводит эти файлы в app.js файл пакета, указанный в конфигурации:

webpack.config.js (одиночный выход)
output: {
  filename: 'app.js'
}

Этот app.js выходной пакет — это единственный файл JavaScript, который содержит исходный код приложения и его зависимости. Вы загрузите его позже с помощью тега <script> в index.html.

Несколько пакетов

Вероятно, вам не нужен один большой пакет всего. Лучше разделить изменчивый код приложения от относительно стабильных модулей кода поставщиков.

Измените конфигурацию так, чтобы у нее были две точки входа, main.ts и vendor.ts:

entry: {
  app: 'src/app.ts',
  vendor: 'src/vendor.ts'
},

output: {
  filename: '[name].js'
}

Webpack строит два отдельных графа зависимостей и создает два файла пакетов, один под названием app.js содержащий только код приложения, и другой под названием vendor.js со всеми зависимостями поставщиков.

[name] в имени вывода — это заполнитель, который плагин Webpack заменяет именами входов, app и vendor. Плагины описаны позже в руководстве.

Чтобы указать Webpack, что должно быть включено в пакет поставщиков, добавьте файл vendor.ts, который импортирует только сторонние модули приложения:

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, ...

Загрузчики

Webpack может объединять любые типы файлов: JavaScript, TypeScript, CSS, SASS, LESS, изображения, HTML, шрифты и т.д. Сам Webpack понимает только файлы JavaScript. Научите его преобразовывать файлы, не являющиеся JavaScript, в эквиваленты JavaScript с помощью загрузчиков. Настройте загрузчики для TypeScript и CSS следующим образом.

rules: [
  {
    test: /\.ts$/,
    loader: 'awesome-typescript-loader'
  },
  {
    test: /\.css$/,
    loaders: 'style-loader!css-loader'
  }
]

Когда Webpack встречает import операторы, такие как следующий, он применяет шаблоны test RegEx.

import { AppComponent } from './app.component.ts';

import 'uiframework/dist/uiframework.css';

Когда шаблон соответствует имени файла, Webpack обрабатывает файл с соответствующим загрузчиком.

Первый import файл соответствует .ts шаблону, поэтому Webpack обрабатывает его с помощью awesome-typescript-loader. Импортированный файл не соответствует второму шаблону, поэтому его загрузчик игнорируется.

Второй import соответствует второму .css шаблону, для которого у вас есть два загрузчика, объединённые символом (!). Webpack применяет объединенные загрузчики справа налево. Итак, он сначала применяет загрузчик css для выравнивания CSS @import и url(...) операторов. Затем он применяет загрузчик style для добавления CSS внутри <style> элементов на странице.

Плагины

Webpack имеет конвейер сборки с чётко определёнными фазами. Используйте плагины, такие как плагин минимизации uglify, для работы с этим конвейером:

plugins: [
  new webpack.optimize.UglifyJsPlugin()
]

Настройка Webpack

После этого краткого ознакомления вы готовы создать собственную конфигурацию Webpack для приложений Angular.

Начните с настройки среды разработки.

Создайте новую папку проекта.

mkdir angular-webpack
cd    angular-webpack

Добавьте эти файлы:

package.json
{
  "name": "angular2-webpack",
  "version": "1.0.0",
  "description": "A webpack starter for Angular",
  "scripts": {
    "start": "webpack-dev-server --inline --progress --port 8080",
    "test": "karma start",
    "build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail"
  },
  "license": "MIT",
  "dependencies": {
    "@angular/common": "~2.4.0",
    "@angular/compiler": "~2.4.0",
    "@angular/core": "~2.4.0",
    "@angular/forms": "~2.4.0",
    "@angular/http": "~2.4.0",
    "@angular/platform-browser": "~2.4.0",
    "@angular/platform-browser-dynamic": "~2.4.0",
    "@angular/router": "~3.4.0",
    "core-js": "^2.4.1",
    "rxjs": "5.0.1",
    "zone.js": "^0.7.4"
  },
  "devDependencies": {
    "@types/node": "^6.0.45",
    "@types/jasmine": "2.5.36",
    "angular2-template-loader": "^0.6.0",
    "awesome-typescript-loader": "^3.0.4",
    "css-loader": "^0.26.1",
    "extract-text-webpack-plugin": "2.0.0-beta.5",
    "file-loader": "^0.9.0",
    "html-loader": "^0.4.3",
    "html-webpack-plugin": "^2.16.1",
    "jasmine-core": "^2.4.1",
    "karma": "^1.2.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-jasmine": "^1.0.2",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-webpack": "^2.0.1",
    "null-loader": "^0.1.1",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.5.2",
    "style-loader": "^0.13.1",
    "typescript": "~2.0.10",
    "webpack": "2.2.1",
    "webpack-dev-server": "2.4.1",
    "webpack-merge": "^3.0.0"
  }
}
src/tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es2015", "dom"],
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}
webpack.config.js
module.exports = require('./config/webpack.dev.js');
karma.conf.js
module.exports = require('./config/karma.conf.js');
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;

Многие из этих файлов должны быть знакомы по другим руководствам по Angular, особенно по руководствам по настройке TypeScript и npm-пакетам.

Webpack, плагины и загрузчики также устанавливаются как пакеты. Они перечислены в обновлённом packages.json.

Откройте окно терминала и установите npm-пакеты.

npm install

Полифилы

Для запуска приложения Angular в большинстве браузеров нужны полифилы, как объясняется в руководстве по Поддержке браузеров.

Полифилы должны быть сгруппированы отдельно от пакетов приложения и поставщиков. Добавьте polyfills.ts в папку src/.

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 and test
  Error['stackTraceLimit'] = Infinity;
  require('zone.js/dist/long-stack-trace-zone');
}
Загрузка полифилов

Загрузите zone.js в начале polyfills.ts, сразу после других плагинов ES6 и метаданных.

Поскольку этот файл пакета загружается первым, polyfills.ts также является хорошим местом для настройки среды браузера для производства или разработки.

Общая настройка

Разработчики обычно имеют отдельные конфигурации для сред разработки, производства и тестирования. Все три имеют много общих настроек.

Объедините общую конфигурацию в файл под названием 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',
    'vendor': './src/vendor.ts',
    'app': './src/main.ts'
  },

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

  module: {
    rules: [
      {
        test: /\.ts$/,
        loaders: [
          {
            loader: 'awesome-typescript-loader',
            options: { configFileName: helpers.root('src', 'tsconfig.json') }
          } , 'angular2-template-loader'
        ]
      },
      {
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'file-loader?name=assets/[name].[hash].[ext]'
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw-loader'
      }
    ]
  },

  plugins: [
    // Workaround for angular/angular#11580
    new webpack.ContextReplacementPlugin(
      // The (\\|\/) piece accounts for path separators in *nix and Windows
      /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
      helpers.root('./src'), // location of your src
      {} // a map of your routes
    ),

    new webpack.optimize.CommonsChunkPlugin({
      name: ['app', 'vendor', 'polyfills']
    }),

    new HtmlWebpackPlugin({
      template: 'src/index.html'
    })
  ]
};

Внутри webpack.common.js

Webpack — это инструмент на основе NodeJS, который считывает конфигурацию из файла JavaScript-модуля commonjs.

Конфигурация импортирует зависимости с помощью require операторов и экспортирует несколько объектов в качестве свойств объекта module.exports.

  • entry — файлы точки входа, которые определяют пакеты.
  • resolve — способ разрешения имён файлов без расширений.
  • module.rules — module — это объект с rules для определения способа загрузки файлов.
  • plugins — создаёт экземпляры плагинов.

entry

Первым экспортом является объект entry:

config/webpack.common.js

  entry: {
    'polyfills': './src/polyfills.ts',
    'vendor': './src/vendor.ts',
    'app': './src/main.ts'
  },

Этот entry объект определяет три пакета:

  • polyfills — полифилы, необходимые для запуска приложений Angular в большинстве современных браузеров.
  • vendor — сторонние зависимости, такие как Angular, lodash и bootstrap.css.
  • app — код приложения.

resolve импорта без расширений

Приложение будет import десятками, если не сотнями, файлов JavaScript и TypeScript. Вы могли бы написать import операторы с явными расширениями, как в этом примере:

import { AppComponent } from './app.component.ts';

Но большинство import операторов вообще не упоминают расширение. Укажите Webpack на разрешение запросов файлов без расширений, поискав соответствующие файлы с расширением .ts или расширением .js (для обычных файлов JavaScript и предварительно скомпилированных файлов TypeScript).

config/webpack.common.js

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

Если Webpack должен разрешать файлы без расширений для стилей и HTML, добавьте .css и .html в список.

module.rules

Правила указывают Webpack, какие загрузчики использовать для каждого файла или модуля:

config/webpack.common.js

module: {
  rules: [
    {
      test: /\.ts$/,
      loaders: [
        {
          loader: 'awesome-typescript-loader',
          options: { configFileName: helpers.root('src', 'tsconfig.json') }
        } , 'angular2-template-loader'
      ]
    },
    {
      test: /\.html$/,
      loader: 'html-loader'
    },
    {
      test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
      loader: 'file-loader?name=assets/[name].[hash].[ext]'
    },
    {
      test: /\.css$/,
      exclude: helpers.root('src', 'app'),
      loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
    },
    {
      test: /\.css$/,
      include: helpers.root('src', 'app'),
      loader: 'raw-loader'
    }
  ]
},
  • awesome-typescript-loader—загрузчик для транспиляции кода Typescript в ES5, руководствуясь файлом tsconfig.json.
  • angular2-template-loader—загружает шаблоны и стили компонентов Angular.
  • html-loader—для шаблонов компонентов.
  • images/fonts—Изображения и шрифты также объединяются.
  • CSS—первый шаблон соответствует стилям всего приложения; второй обрабатывает стили, привязанные к компонентам (те, которые указаны в свойстве metadata компонента styleUrls).

Первый шаблон предназначен для стилей всего приложения. Он исключает файлы .css в каталоге src/app, где находятся стили, привязанные к компонентам. Загрузчик ExtractTextPlugin (описанный ниже) применяет загрузчики style и css к этим файлам.

Второй шаблон фильтрует стили, привязанные к компонентам, и загружает их как строки с помощью raw-loader, что и ожидается от Angular для стилей, указанных в свойстве metadata компонента styleUrls.

Несколько загрузчиков могут быть объединены с использованием массивов.

plugins

Наконец, создайте экземпляры трёх плагинов:

config/webpack.common.js

plugins: [
  // Workaround for angular/angular#11580
  new webpack.ContextReplacementPlugin(
    // The (\\|\/) piece accounts for path separators in *nix and Windows
    /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
    helpers.root('./src'), // location of your src
    {} // a map of your routes
  ),

  new webpack.optimize.CommonsChunkPlugin({
    name: ['app', 'vendor', 'polyfills']
  }),

  new HtmlWebpackPlugin({
    template: 'src/index.html'
  })
]

CommonsChunkPlugin

Пакет app.js должен содержать только код приложения. Весь код поставщиков должен принадлежать пакету vendor.js.

Конечно, код приложения импортирует код поставщиков. Сам по себе Webpack недостаточно умён, чтобы исключить код поставщиков из пакета app.js. За эту работу отвечает CommonsChunkPlugin.

CommonsChunkPlugin определяет иерархию между тремя *chunks*: app -> vendor -> polyfills. Там, где Webpack обнаруживает, что app имеет общие зависимости с vendor , он удаляет их из app. Он бы удалил polyfills из vendor, если бы у них были общие зависимости, но их нет.

HtmlWebpackPlugin

Webpack генерирует ряд js и CSS файлов. Вы *можете* вставить их в index.html *ручно*. Это было бы утомительно и подвержено ошибкам. Webpack может вставить эти скрипты и ссылки за вас с помощью HtmlWebpackPlugin.

Конфигурация для различных сред

Файл конфигурации webpack.common.js выполняет большую часть работы. Создайте отдельные файлы конфигурации для разных сред, которые опираются на webpack.common, объединив в них особенности целевой среды.

Эти файлы, как правило, короткие и простые.

Конфигурация для разработки

Вот файл конфигурации webpack.dev.js для разработки.

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'
  }
});

Для сборки в режиме разработки используется сервер разработки Webpack, настроенный вблизи нижней части файла.

Хотя вы говорите Webpack поместить выходные пакеты в папку dist, сервер разработки держит все пакеты в памяти; он не записывает их на диск. Вы не найдете никаких файлов в папке dist, по крайней мере, не любые сгенерированные из этой *сборки в режиме разработки*.

HtmlWebpackPlugin, добавленный в webpack.common.js, использует publicPath и filename настройки для генерации соответствующих <script> и <link> тегов в index.html.

По умолчанию стили CSS встроены в пакеты Javascript. ExtractTextPlugin извлекает их во внешние файлы .css, которые HtmlWebpackPlugin записывает в качестве тегов <link> в index.html.

Для получения подробной информации об этих и других параметрах конфигурации в этом файле обратитесь к документации Webpack.

Получите код приложения в конце этого руководства и попробуйте:

npm start

Конфигурация для производства

Настройка *производственной* сборки похожа на настройку *для разработки* с несколькими ключевыми изменениями.

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'
  },

  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618
      mangle: {
        keep_fnames: true
      }
    }),
    new ExtractTextPlugin('[name].[hash].css'),
    new webpack.DefinePlugin({
      'process.env': {
        'ENV': JSON.stringify(ENV)
      }
    }),
    new webpack.LoaderOptionsPlugin({
      htmlLoader: {
        minimize: false // workaround for ng2
      }
    })
  ]
});

Вы будете развертывать приложение и его зависимости на реальном сервере производства. Вы не будете развертывать артефакты, необходимые только в режиме разработки.

Поместите файлы выходных пакетов для производства в папку dist.

Webpack генерирует имена файлов с хэшем для кэширования. Благодаря HtmlWebpackPlugin, вам не нужно обновлять файл index.html, когда хэш меняется.

Есть дополнительные плагины:

  • *NoEmitOnErrorsPlugin—останавливает сборку, если возникла ошибка.
  • *UglifyJsPlugin—сжимает пакеты.
  • *ExtractTextPlugin—извлекает встроенные css во внешние файлы, добавляя хэш кэширования в имя файла.
  • *DefinePlugin—используется для определения переменных среды, к которым можно обратиться в приложении.
  • *LoaderOptionsPlugins—для переопределения параметров определенных загрузчиков.

Благодаря DefinePlugin и переменной ENV, определённой вверху, вы можете включить режим Angular для производства так:

if (process.env.ENV === 'production') {
  enableProdMode();
}

Получите код приложения в конце этого руководства и попробуйте:

npm run build

Конфигурация для тестирования

Для запуска юнит-тестов вам не требуется много конфигурации. Вам не нужны загрузчики и плагины, которые вы объявляли для сборок в режиме разработки и производства. Вам, вероятно, не нужно загружать и обрабатывать файлы стилей всего приложения для юнит-тестов, и это замедлит вас; для этих CSS файлов вы будете использовать загрузчик null.

Вы можете объединить конфигурацию для тестов в конфигурацию webpack.common и переопределить части, которых вы не хотите или не нужны. Но может быть проще начать сначала с полностью новой конфигурации.

config/webpack.test.js

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

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

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

  module: {
    rules: [
      {
        test: /\.ts$/,
        loaders: [
          {
            loader: 'awesome-typescript-loader',
            options: { configFileName: helpers.root('src', 'tsconfig.json') }
          } , 'angular2-template-loader'
        ]
      },
      {
        test: /\.html$/,
        loader: 'html-loader'

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

  plugins: [
    new webpack.ContextReplacementPlugin(
      // The (\\|\/) piece accounts for path separators in *nix and Windows
      /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
      helpers.root('./src'), // location of your src
      {} // a map of your routes
    )
  ]
}

Переконфигурируйте Karma для использования Webpack для запуска тестов:

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: ['kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome'],
    singleRun: true
  };

  config.set(_config);
};

Вы не предварительно компилируете TypeScript; Webpack транспилирует файлы TypeScript на лету, в памяти, и передаёт сгенерированный JS напрямую в Karma. Временных файлов на диске нет.

karma-test-shim сообщает Karma, какие файлы загрузить предварительно и подготавливает фреймворк Angular к тестированию с тестовыми версиями поставщиков, которые каждое приложение ожидает загрузить предварительно.

config/karma-test-shim.js

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());

Обратите внимание, что вы *не* загружаете код приложения явно. Вы говорите Webpack найти и загрузить тестовые файлы (файлы, оканчивающиеся на .spec.ts). Каждый файл спецификаций импортирует весь—и только—код исходного кода приложения, который он тестирует. Webpack загружает только *эти* конкретные файлы приложения и игнорирует другие файлы, которые вы не тестируете.

Получите код приложения в конце этого руководства и попробуйте:

npm test

Пробуем

Вот исходный код небольшого приложения, которое собирается с помощью техник Webpack, рассмотренных в этом руководстве.

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);
src/assets/css/styles.css
body {
    background: #0147A7;
    color: #fff;
}
src/app/app.component.ts
import { Component } from '@angular/core';

import '../assets/css/styles.css';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent { }
src/app/app.component.html
<main>
  <h1>Hello from Angular App with Webpack</h1>

  <img src="../assets/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 { }

app.component.html отображает этот загружаемый логотип Angular . Создайте папку с именем images в папке assets проекта, затем щелкните правой кнопкой мыши (Cmd+щелчок на Mac) на изображении и скачайте его в эту папку.

Вот ещё раз файлы TypeScript точки входа, которые определяют пакеты polyfills и vendor.

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 and test
  Error['stackTraceLimit'] = Infinity;
  require('zone.js/dist/long-stack-trace-zone');
}
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, ...

Основные моменты

  • В index.html нет тегов <script> или <link>. HtmlWebpackPlugin вставляет их динамически во время выполнения.

  • AppComponent в app.component.ts импортирует стили всего приложения с помощью простого оператора import.

  • Сам AppComponent имеет свой собственный шаблон html и файл css. WebPack загружает их с помощью вызовов require(). WebPack помещает эти файлы, связанные с компонентами, в пакет app.js тоже. Вы не видите эти вызовы в исходном коде; они добавляются в скрытом режиме плагином angular2-template-loader.

  • vendor.ts состоит из операторов импорта зависимостей поставщиков import, которые управляют пакетом vendor.js. Приложение также импортирует эти модули; они дублировались бы в пакете app.js , если бы CommonsChunkPlugin не обнаружил дублирование и не удалил их из app.js.

Заключение

Вы изучили достаточно Webpack, чтобы настроить сборки в режиме разработки, тестирования и производства для небольшого приложения Angular.

Вы всегда можете сделать больше. Найдите в сети экспертные советы и расширьте свои знания о Webpack.

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://v2.angular.io/docs/ts/latest/guide/webpack.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API