Slim 4 - Webpack



Требования

Введение

Если вы когда-либо уже использовали webpack и не совсем поняли зачем он, вам все же придется прочитать дальше. В этом руководстве Webpack используется для объединения (компиляции, комбинирования и минимизации) веб-ресурсов, таких как компоненты/плагины JavaScript и файлы CSS.

Структура проекта

/                              корневая директория проекта - root
/composer.json
/webpack.config.js             конфиг Webpack
/templates/                    файлы шаблона twig + assets файлы
/templates/home/               
/templates/user/
/public/                       корневая директория вебсервера
/public/index.php              точка входа (application entry point)
/public/assets                 скомпилированые assets файлы (webpack output)
/public/assets/manifest.json   manifest file (required by the webpack twig extension)

Настройки webpack

Создайне новый файл package.json в корне вашего проекта. В этом файле перечислены пакеты, от которых зависит ваш проект:

{
    "name": "my-app",
    "version": "1.0.0",
    "license": "MIT",
    "private": true,
    "dependencies": {
    },
    "devDependencies": {
        "clean-webpack-plugin": "^3.0.0",
        "css-loader": "^3.2.0",
        "file-loader": "^4.2.0",
        "mini-css-extract-plugin": "^0.8.0",
        "optimize-css-assets-webpack-plugin": "^5.0.3",
        "terser-webpack-plugin": "latest",
        "webpack": "^4.40.2",
        "webpack-assets-manifest": "^3.1.1",
        "webpack-cli": "^3.3.9",
        "webpack-manifest-plugin": "^2.0.4"
    }
}

 

Создайте файл webpack.config.js в корне вашего проекта. Это основной файл конфигурации для Webpack:

const path = require('path');
const webpack = require('webpack');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');

module.exports = {
    entry: {
        'home/home-index': './templates/home/home-index.js'
        // тут вы можете подключать другие assets файлы например:
        // 'layout/layout': './templates/layout/layout.js'
    },
    output: {
        path: path.resolve(__dirname, 'public/assets'),
        publicPath: 'assets/',
    },
    optimization: {
        minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
    },
    performance: {
        maxEntrypointSize: 1024000,
        maxAssetSize: 1024000
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ],
    },
    plugins: [
        new CleanWebpackPlugin(),
        new ManifestPlugin(),
        new MiniCssExtractPlugin({
            ignoreOrder: false
        }),
    ],
    watchOptions: {
        ignored: ['./node_modules/']
    },
    mode: "development"
};

Ключевой частью является entry(входной объект): он говорит Webpack  загрузить файл templates/home/home-index.js и следовать всем инструкциям require/import.

Затем он упакует все вместе и - благодаря ключу home/home-index - выведет окончательные файлы home/home-index.js и home/home-index.css в каталог public/assets/. Позже можно добавить  больше JavaScript или CSS для конкретной страницы.

Обратите внимание, что Webpack использует TerserWebpackPlugin для минимизации вашего JavaScript и OptimizeCSSAssetsPlugin для минимизации ваших файлов CSS.

Чтобы установить webpack и все зависимости, выполните в консоли:

npm install

Настройка расширения Twig Webpack

Теперь устанавливаем расширение Twig Webpack через композер:

composer require fullpipe/twig-webpack-extension

Зарегистрируйте расширение WebpackExtension Twig в пределах контейнера Twig::class:

use Psr\Container\ContainerInterface;
use Slim\App;
use Slim\Views\Twig;
// ...

return [
    // Application settings
    'settings' => function () {
        return require __DIR__ . '/settings.php';
    },

    // The Slim app factory
    App::class => function (ContainerInterface $container) {
        AppFactory::setContainer($container);

        return AppFactory::create();
    },

    // The Twig template engine
    Twig::class => function (ContainerInterface $container) {
        $settings = (array)$container->get('settings');
        $twigSettings = $settings['twig'];

        $twig = Twig::create($twigSettings['paths'], $twigSettings['options']);
        // ...

        // The path must be absolute.
        // e.g. /var/www/example.com/public
        $publicPath = (string)$settings['public'];

        // Add extensions
        $twig->addExtension(new \Fullpipe\TwigWebpackExtension\WebpackExtension(
            // The manifest file.
            $publicPath . '/assets/manifest.json',
            // The public path
            $publicPath
        ));

        return $twig;
    },

    // Add more container entries ...
];
  • Первый параметр (manifestFile) определяет путь к  manifest.json file. Также тут можно использовать __PATH__.
  • Следующий параметр  (publicPathJs) определяет путь к итоговым js файлам.
  • Третий параметр (publicPathCss) соответственно определяет путь к css файлам.

Рекомендуется создавать экземпляр Slim приложения внутри контейнера (а не где-то «снаружи»). Просто убедитесь, что при начальной загрузке также используется этот экземпляр приложения из контейнера.

Пример для config/bootstrap.php:

<?php

use DI\ContainerBuilder;
use Slim\App;

require_once __DIR__ . '/../vendor/autoload.php';

$containerBuilder = new ContainerBuilder();

// Add container definitions
$containerBuilder->addDefinitions(__DIR__ . '/container.php');

// Build PHP-DI Container instance
$container = $containerBuilder->build();

// Create App instance
$app = $container->get(App::class);

// Register routes
// ...

// Register middleware
// ...

return $app;

 

Создание assets

Далее, создайте новый файл templates/home/home-index.js сбазовым js кодоми ипортрируйте CSS через require:

require('./home-index.css');

alert('Hello World!');

Создайте новый файл templates/home/home-index.css со стройкой:

body {
    background-color: lightgray;
}

Создайте новый файл twig шаблона templates/layout/layout.twig со следующим содержимым:

<!DOCTYPE html>
<html>
    <head>
        <!-- ... -->
        
        {% block css %}{% endblock %}
    </head>
    <body>
        <!-- ... -->
        {% block content %}{% endblock %}

        {% block js %}{% endblock %}
    </body>
</html>

Создайте еще один файл twig шаблонизатора templates/home/home-index.twig с содержимым:

{% extends "layout/layout.twig" %}

{% block css %}
    {% webpack_entry_css 'home/home-index' %}
{% endblock %}

{% block js %}
    {% webpack_entry_js 'time/time-index' %}
{% endblock %}

{% block content %}
Welcome
{% endblock %}

ВАЖНО: Файл ‘home/home-index’ должен соответствовать первому ключу элемента записи в webpack.config.js

Параметры webpack_entry_css и webpack_entry_js получает url из файла manifest.json webpack и выводит соответствующие html теги. Для примера:

<link type="text/css" href="/assets/home/home-index.css" rel="stylesheet">
<script type="text/javascript" src="/assets/home/home-index.js"></script>  

 

Компиляция assets

Для сборки assets при разработке выполните в консоли команду: 

npx webpack --mode=development

Для компиляции и минификации assets файлов для итогового проекта (production), выполните в консоли команду:

npx webpack --mode=production

Поздравляю! Вы получите 3 новых файла:

  • public/assets/home/home-index.js (содержит весь js код для “home/home-index” )
  • public/assets/home/home-index.css (содержит весь CSS для “home/home-index”)
  • public/assets/manifest.json (содержит все записи и имена файлов)

 

Полезные советы

Пересобрать при изменениях

Webpack может следить и пересобирать все файлы при любых изменениях.

npx webpack --watch

Чтобы остановить процесс слежения webpack нажмите сочетание клавиш Ctrl+C.

Подробнее можно почитать по ссылке:

jQuery настройки

jQuery использует глобальную переменную window.jQuery и псевдоним window. $. Проблема в том, что Webpack обернет все в модули, чтобы защитить глобальную область видимости. По этой причине мы должны вручную привязать экземпляр jQuery к глобальной области.

Чтобы установить jQuery, выполните в консоли:

npm install jquery

Браузер должен загрузить jQuery раньше остальных jQuery плагинов. По этой причине рекомендую подлючать jquery в основной js файл.

Добавьте новый файл в конфиг webpack.config.js:

module.exports = {
    entry: {
        'layout/layout': './templates/layout/layout.js',
        // ...
    },
    // ...
};

Привяжите jQuery к глобальной области видимости в точке входа в ваших шаблонах templates/layout/layout.js:

window.jQuery = require('jquery');
window.$ = window.jQuery;

Добавьте assets ресурсы {% webpack_entry_css 'layout/layout' %} и {% webpack_entry_js 'layout/layout' %} в Twig шаблоны layout/layout.twig:

<!DOCTYPE html>
<html>
    <head>
        <!-- ... -->
        
        {% webpack_entry_css 'layout/layout' %}
        
        {% block css %}{% endblock %}
        
        {% webpack_entry_js 'layout/layout' %}
    </head>
    <body>
        <!-- ... -->
        {% block content %}{% endblock %}

        {% block js %}{% endblock %}
    </body>
</html>

Bootstrap настройки

Bootstrap 4 использует jQuery и Popper.js для JavaScript компонентов (modals, tooltips, popovers etc). Необходимо подключить в первую очередь jQuery.

Для установки Bootstrap, выполните в консоли:

npm install bootstrap

Импортируйте boostrap в глобальную точку входа templates/layout/layout.js:

window.jQuery = require('jquery');
window.$ = window.jQuery;

require('bootstrap');
require('popper.js');
require('bootstrap/dist/css/bootstrap.css');

Fontawesome установка/настройка

Fontawesome довольно-таки популярный набор иконок на все случаи жизни.

Чтобы установить Fontawesome, выполните в консоли:

npm install @fortawesome/fontawesome-free

Также нам понадобиться файл-загрузчик для web шрифтов:

npm install file-loader --save-dev

Мы хотим, чтобы  Fontawesome автоматически копировался в папку с другими assets файлами. Файл-загрузик (file-loader) копирует файлы шрифта в корневую папку сборки.

Подключите Fontawesome в глобальной точке входа templates/layout/layout.js

Можно импортировать все иконки:

require('@fortawesome/fontawesome-free/css/all.min.css');

… или можно подключить отдельные наборы иконок:

require('@fortawesome/fontawesome-free/css/fontawesome.css');
require('@fortawesome/fontawesome-free/css/v4-shims.css');
require('@fortawesome/fontawesome-free/css/regular.css');
require('@fortawesome/fontawesome-free/css/solid.css');
require('@fortawesome/fontawesome-free/css/brands.css');

ВАЖНО: Мы не устанваливаем js зависимости здесь, так как это увеличит размер итогового js файло свыше 1МБ. Нам необходимы только css и файлы веб шрифта для fontawesome.

Чтобы скопировать шрифты в папку assets/webfonts/, добавьте следующее правило в конфиг webpack.config.js:

module: {
        rules: [
            // ...
            {
                test: /\.(ttf|eot|svg|woff|woff2)(\?[\s\S]+)?$/,
                include: path.resolve(__dirname, './node_modules/@fortawesome/fontawesome-free/webfonts'),
                use: {
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'webfonts',
                        publicPath: '../webfonts',
                    },
                }
            },
        ],
    },

SweetAlert2 установка/настройка

SweetAlert2 красивый, адаптивный, оегко изменяемый и расширяемый js компоненты для всплывающих уведомлений.

Чобы установить SweetAlert2, выполните в консоли:

npm install sweetalert2

Импортируйте sweetalert2 и подключите Swal в глобальную область видимости:

window.Swal = require('sweetalert2');

Как пользоваться:

Swal.fire(
  'Good job!',
  'You clicked the button!',
  'success'
);

DataTables установка/настройка

DataTables.net очень гибкий jQuery плагин для работы с табличными данными.

Не забываем в первую очередь настроить сам jQuery.

Для установки DataTables, runвыполните в консоли

npm install datatables.net-bs4 datatables.net-responsive-bs4 datatables.net-select-bs4

Добавьте новое подключение в webpack.config.js:

module.exports = {
    entry: {
        'layout/layout': './templates/layout/layout.js',     // <- jquery 
        'layout/datatables': './templates/layout/datatables.js', // <-- добавьте эту строку
        'user/user-list': './templates/user/user-list.js', // <-- пример файла со списком пользователей
        // other pages ...
    },
    // ...
};

Импортируйте плагин в глобальную точку входа templates/layout/datatables.js:

window.$.fn.DataTable = require('datatables.net-bs4');
require('datatables.net-bs4/css/dataTables.bootstrap4.css');

Создайте новый Twig шаблон templates/user/user-list.twig:

{% extends "layout/layout.twig" %}

{% block css %}
    {% webpack_entry_css 'layout/datatables' %}
{% endblock %}

{% block js %}
    {% webpack_entry_js 'layout/datatables' %}
    {% webpack_entry_js 'user/user-list' %}
{% endblock %}

{% block content %}
  <div id="content" class="container">
        <div class="row">
            <div class="col-md-12">
                <h1><i class="fas fa-user"></i> User list</h1>
                <hr>
                <table id="my-data-table" class="table table-striped table-bordered dt-responsive nowrap dataTable no-footer dtr-inline collapsed">
                    <thead>
                    <tr>
                        <th>Username</th>
                        <th>E-Mail</th>
                        <th>First name</th>
                        <th>Last name</th>
                    </tr>
                    <tfoot></tfoot>
                </table>
                <p></p>
            </div>
        </div>
{% endblock %}

Вызовите плагин в файле templates/user/user-list.js:

$(function() {
    $('#my-data-table').DataTable();
});

 

Babel установка/настройка

Установка:

npm install --save-dev babel-loader @babel/core @babel/preset-env webpack

Добавьте следующие строки в webpack.config.js:

 module: {
        rules: [
            // ...
            {
                test: /\.js$/,
                exclude: path.resolve('node_modules'),
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            ['@babel/preset-env']
                        ]
                    }
                }]
            },
        ],
    },





comments powered by Disqus