Эта статья устарела и уже не актуальна
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
: определяет применяемые плагины
Прежде всего нам надо передать в Webpack исходные файлы, для которых будут создаваться сборки. В данном случае определяются исходные файлы для трех сборок:
entry: { 'polyfills': './src/polyfills.ts', 'app': './src/main.ts' },
То есть сборки polyfills и app указывают на все те файлы, которые были определены выше. Если эти файлы импортируют какие-то другие модули, то импортируемые пакеты также включаются в сборку.
В результате сборки мы должны получить некоторые выходные файлы, что определяется секцией output:
output: { path: path.resolve(__dirname, 'dist'), publicPath: '/', filename: '[name].[fullhash].js' },
Здесь указано, что сборки будут находиться в каталоге dist, и для них будут созданы файлы с названиями сборок. Плейсхолдер [name]
будет передать название сборки,
то есть polyfills или app. Кроме того, в название файла включается хеш-значение с помощью плейсхолдера [fullhash]
на случай, если мы захотим пересоздать файл
без изменения названия сборки.
Секция devServer определяют конфгурацию запускаемого веб-сервера, на котором будет развертываться тестируемое приложение:
devServer: { historyApiFallback: true, port: 8081, open: true }
Значение historyApiFallback: true
указывает, что будет использоваться HTML5 History API. Это может быть полезно, если приложение
использует маршрутизацию.
Опция port
указывает, что веб-сервер будет запускаться на порту 8081, то есть к приложению мы сможем обратиться по адресу
localhost:8081.
open: true
указывает, что при запуске веб-сервера приложение будет автоматически открываться в веб-браузере.
При импорте файлов в модулях и компонентах мы можем не использовать расширение, например:
import {User} from './user';
Чтобы указать, что в подобных случаях мы будем иметь дело с файлами typescript или javascript, применяется секция resolve, в которой перечисляются расширения:
resolve: { extensions: ['.ts', '.js'] }
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
позволяет переопределить поведение других модулей.
В итоге проект будет выглядеть следующим образом:
Теперь, когда все файлы готовы, мы можем запустить проект. Для этого перейдем к командной строке/терминале к каталогу проекта и выполним определенную в package.json команду
npm run dev
По умолчанию webpack-dev-server запускает проект и обращается к нему в браузере:
В данном случае проиходит сборка модулей в памяти. Если мы хотим непосредственно получить файлы сборок, то мы можем выполнить вторую команду из package.json:
npm run build
В итоге в проекте появится каталог dist, в котором будут скомпилированные файлы:
Это все файлы приложения, которые необходимы для работы. Нам же достаточно будет разместить их на каком-нибудь веб-сервере и обратиться к файлу index.html.