Webpack

Эта статья устарела и уже не актуальна

Последнее обновление: 04.05.2023

Webpack представляет популярный инструмент для сборки модулей в один файл. В предыдущих статьях для создания приложения Angular использовалась инфраструктура Angular CLI. Однако в реальности при построении проекта Angular CLI применяет Webpack. Кроме того, Webpack является довольно распространенным инструментом веб-разработки. Теперь рассмотрим, как мы можем собирать проект с помощью Webpack без Angular CLI. Отмечу, что в данном случае мы будем использовать именно версию Webpack 5, которая немного отличается в плане конфигурации от предыдущих версий.

Для использования Webpack создадим новый проект. Определим в проекте новый файл package.json:

{
   "name": "webpackapp",
  "version": "1.0.0",
  "author": "Eugene Popov metanit.com",
  "scripts": {
    "dev": "webpack serve",
    "build": "webpack"
  },
  "dependencies": {
    "@angular/common": "~16.0.0",
    "@angular/compiler": "~16.0.0",
    "@angular/core": "~16.0.0",
    "@angular/forms": "~16.0.0",
    "@angular/platform-browser": "~16.0.0",
    "@angular/platform-browser-dynamic": "~16.0.0",
    "@angular/router": "~16.0.0",
    "rxjs": "7.8.0",
    "zone.js": "~0.13.0"
  },
  "devDependencies": {
    "angular2-template-loader": "~0.6.2",
    "css-loader": "~6.7.0",
    "file-loader": "~6.2.0",
    "html-loader": "~4.2.0",
    "html-webpack-plugin": "~5.5.0",
    "mini-css-extract-plugin": "~2.7.0",
    "raw-loader": "~4.0.2",
    "ts-loader": "~9.4.0",
    "typescript": "~5.0.1",
    "webpack": "~5.80.0",
    "webpack-cli": "5.0.0",
    "webpack-dev-server": "~4.13.0"
  }
}

Секция devDependencies содержит определение пакетов typescript, webpack и webpack-dev-server, которые потребуются при разработке, а также кучу пакетов, которые предназначены, главным образом, для загрузки тех или иных типов файлов.

В секции scripts определены две команды. Первая команда "dev" будет запускать тестовый веб-сервер webpack-dev-server, который в свою очередь будет запускать приложение.

Вторая команда "build" потребуется для компиляции всех необходимых сборок из разрозненных модулей.

И также добавим в папку проекта для управления конфигурацией typescript файл tsconfig.json:

{
    "compilerOptions": {
      "target": "es2022",
      "module": "es2022",
      "moduleResolution": "node",
      "sourceMap": true,
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "lib": [ "es2022", "dom" ],
      "noImplicitAny": true,
      "typeRoots": [
        "node_modules/@types/"
      ]
    },
    "exclude": [
        "node_modules"
    ]
  }

В командной строке/терминале перейдем к папке проекта и выполним команду npm install для установки всех зависимостей:

npm install

Теперь собственно определим файлы приложения. Для этого создадим в проекте каталог src. В этот каталог поместим файл index.html:

<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <title>Angular и Webpack</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <my-app>Загрузка...</my-app>
    </body>
</html>

Это собственно страница веб-приложения, она не содержит подключения никаких скриптов, так как скрипты будут вставлять при сборке через webpack.

Затем в папке src создадим новый файл polyfills.ts:

import 'zone.js/dist/zone';

Это полифил, который необходим для поддержки приложения всеми стандартными браузерами.

Далее в папке src определим папку app. Определим в каталоге src/app новый файл app.component.ts с простеньким компонентом:

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

@Component({
    selector: "my-app",
    standalone: true,
    template: `<h2>Hello Angular! Welcome Webpack!</h2>`
})
export class AppComponent { }

Также добавим в каталог src/app файл модуля app.module.ts:

import {NgModule} from "@angular/core";
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
import {AppComponent} from './app.component';

@NgModule({
	imports:[BrowserModule, FormsModule],
	declarations: [AppComponent],
	bootstrap: [AppComponent]
})
export class AppModule{}

И в конце добавим в каталог src файл main.ts:

import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app/app.module';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

То есть это все те файлы, которые присутствуют в стандартном проекте Angular.

И в завершении добавим в корневой каталог проекта файл webpack.config.js, который будет содержать конфигурацию Webpack:

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
    mode: "development",
    entry: {
        'polyfills': './src/polyfills.ts',
        'app': './src/main.ts'
      },
   output:{
       path: path.resolve(__dirname, 'dist'),     // путь к каталогу выходных файлов - папка public
       publicPath: '/',
       filename: '[name].[fullhash].js'
   },
   devServer: {
    historyApiFallback: true,
    port: 8081,
    open: true
  },
   resolve: {
    extensions: ['.ts', '.js']
  },
   module:{
       rules:[   //загрузчик для ts
           {
               test: /\.ts$/, // определяем тип файлов
               use: [
                {
                    loader: 'ts-loader',
                    options: { configFile: path.resolve(__dirname, 'tsconfig.json') }
                  } ,
                   'angular2-template-loader'
               ]
            }, {
              test: /\.html$/,
              loader: 'html-loader'
            },{
            test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
            loader: 'file-loader',
            options: {
              name: '[name].[fullhash].[ext]',
            }
          },{
            test: /\.css$/,
            exclude: path.resolve(__dirname, 'src/app'),
            use: [
              MiniCssExtractPlugin.loader,
              "css-loader"
            ]
          },{
            test: /\.css$/,
            include: path.resolve(__dirname, 'src/app'),
            loader: 'raw-loader'
          }
       ]
   },
   plugins: [
    new webpack.ContextReplacementPlugin(
        /angular(\\|\/)core/,
        path.resolve(__dirname, 'src'), // каталог с исходными файлами
      {} // карта маршрутов
    ),
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: "[name].css"
    }),
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.LoaderOptionsPlugin({
      htmlLoader: {
        minimize: false
      }
    })
  ]
}

Здесь определены шесть секций:

  • entry: определяет входные файлы для создания сборок

  • output: определяет конфигурацию выходных файлов

  • devServer: конфигурация веб-сервера для тестирования

  • resolve: определяет, как будут обрабатываться файлы, если они не имеют расширений

  • module.rules : определяет загрузчики, которые загружают модули

  • plugins: определяет применяемые плагины

entry

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

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

То есть сборки polyfills и app указывают на все те файлы, которые были определены выше. Если эти файлы импортируют какие-то другие модули, то импортируемые пакеты также включаются в сборку.

output

В результате сборки мы должны получить некоторые выходные файлы, что определяется секцией output:

output: {
		path: path.resolve(__dirname, 'dist'),
		publicPath: '/',
		filename: '[name].[fullhash].js'
},

Здесь указано, что сборки будут находиться в каталоге dist, и для них будут созданы файлы с названиями сборок. Плейсхолдер [name] будет передать название сборки, то есть polyfills или app. Кроме того, в название файла включается хеш-значение с помощью плейсхолдера [fullhash] на случай, если мы захотим пересоздать файл без изменения названия сборки.

devServer

Секция devServer определяют конфгурацию запускаемого веб-сервера, на котором будет развертываться тестируемое приложение:

devServer: {
    historyApiFallback: true,
    port: 8081,
    open: true
  }

Значение historyApiFallback: true указывает, что будет использоваться HTML5 History API. Это может быть полезно, если приложение использует маршрутизацию.

Опция port указывает, что веб-сервер будет запускаться на порту 8081, то есть к приложению мы сможем обратиться по адресу localhost:8081.

open: true указывает, что при запуске веб-сервера приложение будет автоматически открываться в веб-браузере.

resolve

При импорте файлов в модулях и компонентах мы можем не использовать расширение, например:

import {User} from './user';

Чтобы указать, что в подобных случаях мы будем иметь дело с файлами typescript или javascript, применяется секция resolve, в которой перечисляются расширения:

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

module.rules

Webpack понимает только файлы javascript, для всех остальных типов файлов - ts, css и т.д. необходимы специальные инструменты - загрузчики. В данном случае загрузчики определены только для файлов ts и html. Для загрузки файлов typescript применяются загрузчики ts-loader и angular2-template-loader:

{
	test: /\.ts$/,
	use: [{
		loader: 'ts-loader',
        options: { configFile: path.resolve(__dirname, 'tsconfig.json') }
		},'angular2-template-loader'
	]
}

ts-loader позволяет загружать код Typescript в соответствии с конфигурацией из файла tsconfig.json.

angular2-template-loader загружает шаблоны и стили Angular.

Для загрузки файлов html, которые используются компонентами, применяется загрузчик html-loader:

{
    test: /\.html$/,
    loader: 'html-loader'
}

Для загрузки различных изображений, шрифтов и прочих ресурсов применяется загрузчик file-loader:

{
    test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
    loader: 'file-loader',
    options: {
              name: '[name].[fullhash].[ext]',
	}
}

Для использования css применяются два загрузчика:

{
    test: /\.css$/,
    exclude: path.resolve(__dirname, 'src/app'),
	use: [
		MiniCssExtractPlugin.loader,
		"css-loader"
	]
},
{
    test: /\.css$/,
    include: path.resolve(__dirname, 'src/app'),
    loader: 'raw-loader'
}

Плагины

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

Плагин ContextReplacementPlugin позволяет управлять путями к файлам вне зависимости используем мы Windows или Linux.

HtmlWebpackPlugin позволяет автоматически внедрить создаваемые сборки javascript или css в файл html. Хотя мы можем и вручную определить подключение на веб-странцу скриптов и стилей.

Плагин MiniCssExtractPlugin извлекает css-файлы и добавляет в их название хеш-значение, как и в случае с js-файлами.

Плагин NoEmitOnErrorsPlugin останавливает дальнейшую сборку модулей, если произошла ошибка.

Плагин LoaderOptionsPlugin позволяет переопределить поведение других модулей.

Запуск проекта

В итоге проект будет выглядеть следующим образом:

Webpack 5 в Angular 17

Теперь, когда все файлы готовы, мы можем запустить проект. Для этого перейдем к командной строке/терминале к каталогу проекта и выполним определенную в package.json команду

npm run dev

По умолчанию webpack-dev-server запускает проект и обращается к нему в браузере:

Webpack-dev-server в Angular

В данном случае проиходит сборка модулей в памяти. Если мы хотим непосредственно получить файлы сборок, то мы можем выполнить вторую команду из package.json:

npm run build

В итоге в проекте появится каталог dist, в котором будут скомпилированные файлы:

Сборка в Webpack и Angular 17

Это все файлы приложения, которые необходимы для работы. Нам же достаточно будет разместить их на каком-нибудь веб-сервере и обратиться к файлу index.html.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850