После прочтения ряда статей (например, этой) решил перейти на современный подход с использованием Node.js при написании простых сайтов с подхода «динозавров». Ниже представлен разбор примера сборки простого статического сайта с помощью Webpack 4. Статья написана, так как инструкции с решением моей задачи не нашел: пришлось собирать всё по кусочкам.


Постановка задачи


Сайт представляет собой простой набор HTML-страниц со своим CSS стилями и файлом JavaScript. Необходимо написать проект, который бы собирал наш сайт из исходников:


  • из SASS (точнее SCSS) файлов формируется один CSS файл;
  • из различных JavaScript библиотек и пользовательского кода формируется один JavaScript файл;
  • HTML страницы собираются с помощью шаблонизатора, где содержимое шапки и футера можно разнести по отдельным файлам.

В собранном сайте не должны использоваться React, Vue.js.


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


Для примера будет сверстано несколько страничек на базе Bootstrap 4. Но это только для примера.


Предполагается, что Node.js установлен (в Windows просто скачивается установщик и устанавливается в стиле «далее, далее»), и вы умеете работать с командной строкой.


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


Общая структура проекта представлена ниже:


.
+-- dist                 - папка, куда будет собираться сайт
+-T src                  - папка с исходниками сайта
¦ +-- favicon            - папка с файлами иконок для сайта
¦ +-- fonts              - папка со шрифтами
¦ +-T html               - папка заготовок HTML страниц
¦ ¦ +-- includes         - папка с встраиваемыми шаблонами (header, footer)
¦ ¦ L-- views            - папка с самими HTML страницами
¦ +-- img                - папка с общими изображениями (логотип, иконки и др.)
¦ +-- js                 - папка с JavaScript файлами
¦ +-- scss               - папка с SСSS файлами
¦ L-- uploads            - папка с файлами статей (картинки, архивы и др.)
+-- package.json         - файл настроек Node.js
L-- webpack.config.js    - файл настроек Webpack

Та же структура, но с показом файлов, которые присутствуют в примере:
.
+-- dist
+-T src
¦ +-T favicon
¦ ¦ L-- favicon.ico
¦ +-T fonts
¦ ¦ L-- Roboto-Regular.ttf
¦ +-T html
¦ ¦ +-T includes
¦ ¦ ¦ +-- footer.html
¦ ¦ ¦ L-- header.html
¦ ¦ L-T views
¦ ¦   +-- index.html
¦ ¦   L-- second.html
¦ +-T img
¦ ¦ L-- logo.svg
¦ +-T js
¦ ¦ L-- index.js
¦ +-T scss
¦ ¦ L-- style.scss
¦ L-T uploads
¦   L-- test.jpg
+-- package.json
L-- webpack.config.js

Под favicon выделена целая папка, так как в современном web обычным одним ico файлом не обойтись. Но для примера используется только этот один файл.


Спорным решением может показаться разделение картинок на две папки: img и uploads. Но здесь использовал идеологию расположения файлов из Wordpress. На мой взгляд, кидать все изображения в одну папку — не очень хорошая идея.


Для работы с проектом использую Visual Studio Code, которым очень доволен. Особенно мне нравится, что командная строка встроена в программу и вызывается через Ctrl + `.



Сделаем болванку Node.js проекта. Для этого создадим папку нашего проекта с вышеописанной структурой и перейдем в неё в командной строке, где вызовем команду для создания файла package.json.


npm init

На все вопросы можно просто отвечать, нажимая Enter, если заполнять подробную информацию не хочется.


Установим три общих пакета, которые нам потребуются в любом случае: webpack, webpack-cli (работу с командной строкой в webpack вынесли в отдельный пакет) и webpack-dev-server (для запуска локального сервера, чтобы в браузере сразу отображались сохраненные изменения проекта).


npm install webpack webpack-cli webpack-dev-server --save-dev

Файл package.json сейчас выглядит примерно так:
{
  "name": "static-site-webpack-habrahabr",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.11",
    "webpack-dev-server": "^3.1.1"
  }
}

Также создастся файл package-lock.json, который вообще не трогаем. Но в git репозиторий добавлять этот файл нужно, в отличии от папки node_modules, которую нужно прописать в файле .gitignore, если пользуетесь git.


Собираем JavaScript


Так как Webpack создан в первую очередь для сборки js файлов, то эта часть будем самой простой. Чтобы можно было писать javascript в современном виде ES2015, который не поддерживается браузерами, поставим пакеты babel-core, babel-loader, babel-preset-env.


npm install babel-core babel-loader babel-preset-env --save-dev

После создаем файл настроек webpack.config.js с таким содержимым:


const path = require('path');

module.exports = {
  entry: [
    './src/js/index.js',
  ],
  output: {
    filename: './js/bundle.js'
  },
  devtool: "source-map",
  module: {
    rules: [{
        test: /\.js$/,
        include: path.resolve(__dirname, 'src/js'),
        use: {
          loader: 'babel-loader',
          options: {
            presets: 'env'
          }
        }
      },
    ]
  },
  plugins: [
  ]
};

В разделе entry (точки входа) указываем, какой js файл будем собирать, в разделе output указываем путь в папке dist, куда будем помещаться собранный файл. Обратите внимание, что в webpack 4 в пути output саму папку dist указывать не нужно! И да, как же мне не нравится, что в одном файле webpack в одних случаях нужно писать относительный путь, в других случаях относительный путь в специальной папке, в третьих случаях нужен уже абсолютный путь (например, его получаем этой командой path.resolve(__dirname, 'src/js')).


Также указано значение параметра devtool, равное: source-map, что позволит создавать карты исходников для js и css файлов.


Для обработки конкретных файлов (по расширению, по месторасположению) в webpack создаются правила в разделе rules. Сейчас у нас там стоит правило, что все js файлы пропускаем через транслятор Babel, который преобразует наш новомодный ES2015 в стандартный javascript вариант, понятный браузерам.


В нашем тестовом примере мы верстаем наши странице на Boostrap 4. Поэтому нам нужно будет установить три пакета: bootstrap, jquery, popper.js. Второй и третий пакет мы устанавливаем по требованию Bootstrap.


npm install bootstrap jquery popper.js --save

Обратите внимание на то, что эти три пакета нам нужны именно для самого сайта, а не для его сборки. Поэтому эти пакеты мы устанавливаем с флагом --save, а не --save-dev.


Теперь можно приступить к написанию нашего index.js файла:


import jQuery from 'jquery';
import popper from 'popper.js';
import bootstrap from 'bootstrap';

jQuery(function() {
    jQuery('body').css('color', 'blue');
});

В качестве примера пользовательского кода js просто перекрасили цвет текста на синий.


Теперь можно перейти к сборке js файла. Для этого в файле package.json в разделе scripts пропишем следующие npm скрипты:


  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "watch": "webpack --mode development --watch",
    "start": "webpack-dev-server --mode development --open"
  },

Теперь при запуске в командной строке строчки npm run dev произойдет сборка проекта (css и html файлы потом также будут собираться этой командой), и в папке /dist/js появятся файлы bundle.js и bundle.js.map.


При запуске команды npm run build также произойдет сборка проекта, но уже итоговая (с оптимизацией, максимальной минимизацией файла), которую можно выкладывать на хостинг.


При запуске npm run watch запускается режим автоматического просмотра изменений файлов проекта с автоматическим допостроением измененных файлов. Да, чтобы в командной строке отключить этот режим (например, чтобы можно было написать другие команды) можно нажать Ctrl + C (как минимум в PowerShell).


При запуске npm run start запустится локальный сервер, который запустит html страницу и также будет отслеживать изменения в файлах. Но пока этой командой не пользуемся, так как сборку html страниц не добавили.


Режим построения проекта создает или переписывает файлы в папке dist. Но во время разработки проекта при разных сборках файлы могут переименовываться, удаляться. И Webpack не будет следить, чтобы уже ненужные файлы, оставшиеся после предыдущих сборок, удалялись из папки dist. Поэтому добавим еще один пакет clean-webpack-plugin, который будет очищать папку dist перед каждой сборкой проекта.


npm install clean-webpack-plugin --save-dev

Внесем изменения в файл webpack.config.js.


...
const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  ...
  plugins: [
      new CleanWebpackPlugin(['dist']),
  ]
};

Сборка CSS файла


CSS файл будем собирать из SCSS файлов, под которые у нас зарезервирована папка src/scss. В ней создадим файл style.scss, например, со следующим содержимым:


$font-stack: -apple-system, BlinkMacSystemFont,Roboto,'Open Sans','Helvetica Neue',sans-serif;

@import "~bootstrap/scss/bootstrap";

@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400;
  src: url(../fonts/Roboto-Regular.ttf);
}

body {
  font-family: $font-stack;
  #logo {
    width: 10rem;
  }
  .container {
    img {
      width: 20rem;
    }
  }
}

Обратите внимание на то, что стили Bootstrap подключаем не через его CSS файл, а через SСSS (@import "node_modules/bootstrap/scss/bootstrap" @import "~bootstrap/scss/bootstrap";), который позволит в случае надобности переписать те или иные свойства библиотеки, использовать его миксины и др. Но что печалит. Если при сборке js файла при подключении js файла Bootstrap библиотеки Webpack знает, где находятся нужные файлы, то при подключении стилей нужно указывать путь к папке в node_modules.


Для обработки css файлов нам будут нужны следующие модули: node-sass, sass-loader, css-loader и extract-text-webpack-plugin (говорят, что в следующей версии Webpack в последнем плагине надобность отпадет).


Важно! На момент написания статьи плагин extract-text-webpack-plugin в стабильной версии не умеет работать с Webpack 4. Поэтому нужно устанавливать его beta версию через @next:


npm install node-sass sass-loader css-loader extract-text-webpack-plugin@next --save-dev

Надеюсь, что вскоре можно будет устанавливать все плагины по нормальному:


npm install node-sass sass-loader css-loader extract-text-webpack-plugin --save-dev

В webpack.config.js добавим следующие изменения:


...
const ExtractTextPlugin = require("extract-text-webpack-plugin");
...

module.exports = {
  entry: [
    ...
    './src/scss/style.scss'
  ],
  ...
  module: {
    rules: [{
      ...
      {
        test: /\.(sass|scss)$/,
        include: path.resolve(__dirname, 'src/scss'),
        use: ExtractTextPlugin.extract({
          use: [{
              loader: "css-loader",
              options: {
                sourceMap: true,
                minimize: true,
                url: false
              }
            },
            {
              loader: "sass-loader",
              options: {
                sourceMap: true
              }
            }
          ]
        })
      },
    ]
  },
  plugins: [
    new ExtractTextPlugin({
      filename: './css/style.bundle.css',
      allChunks: true,
    }),
    ...
  ]
};

Обратите внимание на то, что в точках входа entryмы добавили новый входной файл style.scss, но выходной файл указали не в output, а в вызове плагина ExtractTextPlugin в разделе plugins. Включаем поддержку карт источников sourceMap для пакетов sass-loader и css-loader.


Также можно заметить, что тут нет пакета style-loader, который чаще всего упоминается при работе с css в Webpack. Данный пакет встраивает css код в файл HTML, что может быть удобно для одностраничных приложений, но никак не для многостраничного.


И самый спорный момент. Для пакета css-loader мы добавили параметр url, равный false. Зачем? По умолчанию url=true, и если Webpack при сборке css находит ссылки на внешние файлы: фоновые изображения, шрифты (например, в нашем случае есть ссылка на файл шрифта url(../fonts/Roboto-Regular.ttf)), то он эти файлы попросит как-то обработать. Для этого используют чаще всего пакеты file-loader (копирует файлы в папку сборки) или url-loader (маленькие файлы пытается встроить в HTML код). При этом прописанные относительные пути к файлам в собранном css могут быть изменены.


Но с какой проблемой столкнулся на практике. Есть у меня папка src/scss с SСSS кодом. Есть папка src/img с картинками, на которые ссылаются в SСSS коде. Всё хорошо. Но, например, мне потребовалось подключить на сайт стороннюю библиотеку (например, lightgallery). SCSS код у неё располагается в папке node_modules/lightgallery/src/sass, который ссылается на картинки из папки node_modules/lightgallery/src/img через относительные пути. И если добавить стили библиотеки в наш style.scss, то file-loader будет искать картинки библиотеки lightgallery в моей папке src/img, а не там, где они находятся. И побороть я это не смог.


Поэтому установкой url=false говорим, что все ссылки на файлы в SCSS коде не трогаем, пути не меняем, никакие файлы не копируем и не встраиваем: с ними разберемся потом отдельно. Возможно, это решение плохое, и вы предложите более правильный подход.


Сборка HTML страниц


Перейдем к самому веселому: к сборке HTML страниц, где у меня возникли самые большие трудности.


Для сборки HTML страниц будем использовать плагин html-webpack-plugin, который поддерживает различные виды шаблонизаторов. Также нам потребуются пакет raw-loader.


npm install html-webpack-plugin raw-loader --save-dev

В качестве шаблонизатора HTML будем использовать шаблонизатор по умолчанию lodash. Вот так будет выглядеть типичная HTML страница до сборки:


<% var data = {
  title: "Заголовок | Проект",
  author: "Harrix"
}; %>
<%= _.template(require('./../includes/header.html'))(data) %>

<p>text</p>

<%= _.template(require('./../includes/footer.html'))(data) %>

Вначале в переменной data прописываем все наши переменные страницы, которые хотим использовать на этой странице. Потом встраиваем шаблоны шапки и футера через _.template(require()).


Важное уточнение. В статьях про сборку HTML страниц через html-webpack-plugin обычно подключают встраиваемые шаблоны просто через команду:


require('html-loader!./../includes/header.html')

Но при этом в этих встраиваемых шаблонах синтаксис lodash работать не будет (я так и не понял, почему так происходит). И данные из переменной data туда не передадутся. Поэтому принудительно говорим webpack, что мы встраиваем именно шаблон, который надо обработать как lodash шаблон.


Теперь мы можем использовать полноценные lodash синтаксис в встраиваемых шаблонах. В коде файла header.html ниже через <%=title%> печатаем заголовок статьи.


<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="shortcut icon" href="favicon/favicon.ico">
    <link rel="stylesheet" href="css/style.bundle.css">

    <title><%=title%></title>
  </head>
  <body>
    <header><img src="img/logo.svg" id="logo"></header>

В пакете html-webpack-plugin есть возможность генерировать несколько HTML страниц:


 plugins: [
    new HtmlWebpackPlugin(), // Generates default index.html
    new HtmlWebpackPlugin({  // Also generate a test.html
      filename: 'test.html',
      template: 'src/assets/test.html'
    })
  ]

Но прописывать для каждой страницы создание своего экземпляра плагина точно не есть хорошо. Поэтому автоматизируем этот процесс, найдя все HTML файлы в папке src/html/views и создадим для них свои версии new HtmlWebpackPlugin().


Для этого в файле webpack.config.js внесем следующие изменения:


...
const HtmlWebpackPlugin = require('html-webpack-plugin');
const fs = require('fs')

function generateHtmlPlugins(templateDir) {
  const templateFiles = fs.readdirSync(path.resolve(__dirname, templateDir));
  return templateFiles.map(item => {
    const parts = item.split('.');
    const name = parts[0];
    const extension = parts[1];
    return new HtmlWebpackPlugin({
      filename: `${name}.html`,
      template: path.resolve(__dirname, `${templateDir}/${name}.${extension}`),
      inject: false,
    })
  })
}

const htmlPlugins = generateHtmlPlugins('./src/html/views')

module.exports = {
  module: {
      ...
      {
        test: /\.html$/,
        include: path.resolve(__dirname, 'src/html/includes'),
        use: ['raw-loader']
      },
    ]
  },
  plugins: [
    ...
  ].concat(htmlPlugins)
};

Функция generateHtmlPlugins будет осуществлять поиск всех HTML страниц. Обратите внимание, что в коде функции есть настройка inject: false, которая говорит Webpack, что не нужно встраивать ссылки на js и css файл в HTML код самостоятельно: мы сделаем всё сами вручную в шаблонах header.html и footer.html.


Также нужно отметить, что встраиваемые шаблоны обрабатываются плагином raw-loader (содержимое файла просто загрузить как текст), а не html-loader, как чаще всего предлагают. И также, как в случае с CSS, не использую пакеты file-loader или url-loader.


И остается последний необязательный момент для работы с HTML. JavaScript файл и CSS файл у нас будут минимифицроваться. А вот HTML файлы хочу, наоборот, сделать красивыми и не минифицировать. Поэтому после сборки всех HTML файлов хочется пройтись по ним каким-то beautify плагином. И тут меня ждала подстава: не нашел способа как это сделать в Webpack. Проблема в том, что обработать файлы нужно после того, как будут вставлены встраиваемые шаблоны.


Нашел пакет html-cli, который может это сделать независимо от Webpack. Но у него 38 установок в месяц. То есть это означает два варианта: либо никому не нужно приводить к красивому внешнему виду HTML файлы, либо есть другое популярное решение, о котором я не знаю. А ради только одной этой функции Gulp прикручивать не хочется.


Устанавливаем этот плагин:


npm install html-cli --save-dev

И в файле package.json прописываем еще два скрипта, которые после работы Webpack будут приводить к красивому внешнему виду HTML файлы с установкой табуляции в два пробела.


  "scripts": {
    "build-and-beautify": "webpack --mode production && html dist/*.html --indent-size 2",
    "beautify": "html dist/*.html --indent-size 2"
  },

Поэтому для итоговой сборки рекомендую использовать не команду *npm run build, а команду npm run build-and-beautify.


Копирование оставшихся файлов


Мы сгенерировали js, css файлы, HTML страницы. Остались файлы изображений, шрифтов и др., которые мы не трогали и сознательно не копировали через file-loader или url-loader. Поэтому скопируем все оставшиеся папки через плагин copy-webpack-plugin:


npm install copy-webpack-plugin --save-dev

В файле webpack.config.js внесем изменения:


...
const HtmlWebpackPlugin = require('html-webpack-plugin');
...

module.exports = {
  ...
  plugins: [
  ...
    new CopyWebpackPlugin([{
        from: './src/fonts',
        to: './fonts'
      },
      {
        from: './src/favicon',
        to: './favicon'
      },
      {
        from: './src/img',
        to: './img'
      },
      {
        from: './src/uploads',
        to: './uploads'
      }
    ]),
  ]...
};

Всё. Теперь командой npm run build-and-beautify собираем проект и в папке dist появится собранный статический сайт.



Итоговые файлы


Файл package.json:
{
  "name": "static-site-webpack-habrahabr",
  "version": "1.0.0",
  "description": "HTML template",
  "main": "src/index.js",
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "build-and-beautify": "webpack --mode production && html dist/*.html --indent-size 2",
    "watch": "webpack --mode development --watch",
    "start": "webpack-dev-server --mode development --open",
    "beautify": "html dist/*.html --indent-size 2"
  },
  "dependencies": {
    "bootstrap": "^4.0.0",
    "jquery": "^3.3.1",
    "popper.js": "^1.13.0"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.3",
    "babel-preset-env": "^1.6.1",
    "clean-webpack-plugin": "^0.1.18",
    "copy-webpack-plugin": "^4.5.0",
    "css-loader": "^0.28.9",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "html-cli": "^1.0.0",
    "html-webpack-plugin": "^3.0.4",
    "node-sass": "^4.7.2",
    "raw-loader": "^0.5.1",
    "sass-loader": "^6.0.6",
    "webpack": "^4.0.1",
    "webpack-cli": "^2.0.10",
    "webpack-dev-server": "^3.1.0"
  }
}

Файл webpack.config.js:
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin')
const fs = require('fs')

function generateHtmlPlugins(templateDir) {
  const templateFiles = fs.readdirSync(path.resolve(__dirname, templateDir));
  return templateFiles.map(item => {
    const parts = item.split('.');
    const name = parts[0];
    const extension = parts[1];
    return new HtmlWebpackPlugin({
      filename: `${name}.html`,
      template: path.resolve(__dirname, `${templateDir}/${name}.${extension}`),
      inject: false,
    })
  })
}

const htmlPlugins = generateHtmlPlugins('./src/html/views')

module.exports = {
  entry: [
    './src/js/index.js',
    './src/scss/style.scss'
  ],
  output: {
    filename: './js/bundle.js'
  },
  devtool: "source-map",
  module: {
    rules: [{
        test: /\.js$/,
        include: path.resolve(__dirname, 'src/js'),
        use: {
          loader: 'babel-loader',
          options: {
            presets: 'env'
          }
        }
      },
      {
        test: /\.(sass|scss)$/,
        include: path.resolve(__dirname, 'src/scss'),
        use: ExtractTextPlugin.extract({
          use: [{
              loader: "css-loader",
              options: {
                sourceMap: true,
                minimize: true,
                url: false
              }
            },
            {
              loader: "sass-loader",
              options: {
                sourceMap: true
              }
            }
          ]
        })
      },
      {
        test: /\.html$/,
        include: path.resolve(__dirname, 'src/html/includes'),
        use: ['raw-loader']
      },
    ]
  },
  plugins: [
    new ExtractTextPlugin({
      filename: './css/style.bundle.css',
      allChunks: true,
    }),
    new CleanWebpackPlugin(['dist']),
    new CopyWebpackPlugin([{
        from: './src/fonts',
        to: './fonts'
      },
      {
        from: './src/favicon',
        to: './favicon'
      },
      {
        from: './src/img',
        to: './img'
      },
      {
        from: './src/uploads',
        to: './uploads'
      }
    ]),
  ].concat(htmlPlugins)
};

Файл шаблона index.html:
<% var data = {
  title: "Заголовок | Проект",
  author: "Harrix"
}; %>
<%= _.template(require('./../includes/header.html'))(data) %>

<div class="container">
  <p>Первая страница.</p>
  <p><img src="uploads/test.jpg"></p>
</div>

<%= _.template(require('./../includes/footer.html'))(data) %>

Файл шаблона шапки header.html:
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="shortcut icon" href="favicon/favicon.ico">
    <link rel="stylesheet" href="css/style.bundle.css">

    <title><%=title%></title>
  </head>
  <body>
    <header><img src="img/logo.svg" id="logo"></header>

Файл шаблона footer.html:
<footer><%=author%></footer>

<script src="js/bundle.js"></script>
</body>
</html>

Сгенерированный index.html:
<!doctype html>
<html lang="ru">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <link rel="shortcut icon" href="favicon/favicon.ico">
  <link rel="stylesheet" href="css/style.bundle.css">

  <title>Заголовок | Проект</title>
</head>

<body>
  <header><img src="img/logo.svg" id="logo"></header>

  <div class="container">
    <p>Первая страница.</p>
    <p><img src="uploads/test.jpg"></p>
  </div>

  <footer>Harrix</footer>

  <script src="js/bundle.js"></script>
</body>

</html>

Исходники


Ссылка на репозиторий с рассмотренным проектом.

Комментарии (65)


  1. anttoshka
    13.03.2018 10:29

    Спасибо, как раз на днях занимался подобным вопросом. Ранее читал, что сборка webpack-ом стилей, html и т.п. медленнее чем галпом. Вы не пробовали сравнить быстродействие? У меня есть отдельно настроенная сборка галп+вебпак с шаблонизатором jade. Так там при большом количестве jade миксинов пересборка длится ощутимое время. Если же webpack 4 покажет лучшее быстродействие — стоит на него в таком случае переезжать.


    1. PaulZi
      13.03.2018 14:26
      +1

      gulp быстрее, однако webpack это несколько иной инструмент. Webpack собирает бандлы с учётом зависимостей и умеет tree-snaking. То есть если типичный сценарий с gulp собираем все стили в одном файлы, скрипты в другом. С вебпаком, если у вас есть некий компонент, которому требуют скрипты и стили, а также имеет зависимости, то вы все стили и зависимости подключаете непосредственно в скрипте этого компонента. Поэтому если вдруг вам компонент больше не нужен будет, и вы перестанете его использовать, он у вас перестанет попадать в бандл.


  1. SevenLines
    13.03.2018 12:06

    А использовались ли какие-нибудь фичи нового webpack? А то по названию как будто упор на 4 версию идёт. А с виду тот же третий.


    1. eplaksin
      13.03.2018 14:15
      +1

      из новых фич: сборка с использованием флага --mode


    1. Harrix Автор
      13.03.2018 17:16

      Как уже отметили, режимы --mode development и --mode production. Также отсутствие необходимости указывать паку dist в путях в файле webpack.config.js. А также отсутствие некоторых плагинов (это скорее антифича). Например, jshint пока прикрутить нельзя, так как jshint-loader не работает с новым Webpack.


      1. SevenLines
        13.03.2018 17:52

        eplaksin, Harrix, спасибо.
        Тут недавно статья была про новый вебпак, и как там все здорово будет. А по сути изменения получаются скорее косметические. Я то думал что будет какой-то режим сборки из коробки, без возни с конфигами, но его нет. И в результате, по моим личным ощущениям, получается, что использовать webpack что 3-ий, что 4-ый, для сбора статического сайта это все таки небольшой оверхед.


        1. Harrix Автор
          13.03.2018 17:57

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

          Разумеется, для полноценного статического сайта куда лучше подойдет специализированный инструмент, как тот же Jekyll. Но и там те же css и js надо будет кем-то собирать. И тогда появляется связка Jekyll + webpack или Jekyll + gulp. Вот и решил для простых вариантов обойтись одним инструментом.


  1. sinneren
    13.03.2018 12:26

    `new CleanWebpackPlugin(['dist', 'build']),`
    зачем build здесь, ведь эта папка не фигурирует нигде. Потом, столько мусора, в bundle.js есть пути до scss. Зачем…


    1. Harrix Автор
      13.03.2018 17:28

      Ошибку с CleanWebpackPlugin поправил. Спасибо!

      А вот про мусор не понял. В bundle.js нет упоминаний про scss. А вы как собирали проект? Через npm run dev или npm run build? В первом случае bundle.js будет содержать много мусорного, так как сборка происходит в режиме разработки.


      1. sinneren
        14.03.2018 09:48

        А, да, это я через dev.


  1. PaulZi
    13.03.2018 14:17
    +1

    Но что печалит. Если при сборке js файла при подключении js файла Bootstrap библиотеки Webpack знает, где находятся нужные файлы, то при подключении стилей нужно указывать путь к папке в node_modules.

    Можно писать так:


    @import "~bootstrap/scss/bootstrap";

    по крайней мере node_modules не надо писать. Путь внутри пакета конечно придётся писать, т. к. в package.json пакета нет ключа "main" для стилей.


    1. Harrix Автор
      13.03.2018 17:38

      Спасибо! Исправил и в репозитории, и в статье.


  1. DexterHD
    13.03.2018 14:38

    После прочтения ряда статей (например, этой) решил перейти на современный подход с использованием Node.js при написании простых сайтов с подхода «динозавров».

    Это сарказм?? Перед вами бизнес (вы сами) поставил простейшую задачу:
    Сайт представляет собой простой набор HTML-страниц со своим CSS стилями и файлом JavaScript

    Ваш репозиторий с установленными зависимостями весит 177 MB..
    Война и Мир в HTML будет весить не более 20 Мб. 2300 зависимостей!
    Вот дерево зависимостей которые вы для этого подтянули, оно не умещается в комментарий:
    gist.github.com/DexterHD/9ed32eedf9412e7c1fdfaf6a1c458fae
    И это все чтобы создать набор из HTML страниц с несколькими CSS и JS??? Серьезно Современный подход??


    1. tbopec
      13.03.2018 16:33

      Скомпилированные js, css весят 155 KB и 118 KB соответственно.
      Некомпилированные js, scss, шаблоны — несколько килобайт.

      Все остальное — использованные библиотеки, плюс «компиляторы» и тп. Считать их размер в размер репозитория некорректно.

      К примеру, в .Net вы тоже считаете вес всего фреймворка, .Net компиляторов — это же тоже зависимости? Затем зависимости следующего уровня — API операционной системы, в общем операционную систему, компилятор в машинные команды, ещё кучи библиотек.


    1. Harrix Автор
      13.03.2018 17:44

      В реальности собирается чуть посложнее сайт, но да. Современный подход, к сожалению или к счастью, выглядит так. От количества файлов в node_modules у самого глаза на лоб лезут. А пока собирал проект по кусочкам — обматерил всех и вся. Но, представьте, что папки node_modules нет. И она заменена на обычное приложение, которое весит все те же 177 Мб и выполняет тоже самое. В этом случае такой жесткой критики не будет.

      А по правде говоря меня очень даже устраивала определенное время Koala для решения задачи сборки CSS из SASS и минификации js файлов. Но потом появились хотелки, которые она уже не могла решать (та же шаблонизация HTML). Вот и появился повод разобраться в «современном подходе». Но я уверен, что в ближайшие годы многое изменится.


      1. redfs
        13.03.2018 20:21

        Современный подход, к сожалению или к счастью, выглядит так
        Вы ошибаетесь. Подход сам по себе не может быть «современным» или «олдовым». Любой подход определяется выбором правильного инструмента для реализации. Вы выбрали современный инструмент, но это вовсе не значит, что этот инструмент обеспечил правильный подход и правильное/оптимальное решение вашей задачи.


        1. Harrix Автор
          13.03.2018 20:44

          Подход сам по себе не может быть «современным» или «олдовым».

          Вы выбрали современный инструмент


          Вы сами себе противоречите. Есть современные и есть олдовые подходы. А то, что современный подход является оптимальным решением — я этого нигде не говорил. Например, серьезный статический сайт, на подобии Jekyll не написать (хотя для таких задач я предпочту динамический сайт, но это тема другого холивара). А сам webpack мне очень многим не нравится. И я уверен, что на смену ему придет что-то другое.


          1. redfs
            13.03.2018 21:52

            Вы сами себе противоречите… А то, что современный подход является оптимальным решением — я этого нигде не говорил.
            Вроде нет противоречия. Поясню. Я исхожу от задачи, озвученной вами в статье. Задача решена, но плохо, хоть и современными методами.

            Если бы ваша постановка задачи выглядела как-то так:
            Задача (цель): Изучить современные технологии (webpack)
            Способ решения: Собрать простой статический сайт с помощью webpack 4.
            то можно было бы сказать, что задача решена хорошо.


            1. Harrix Автор
              13.03.2018 21:58

              Почему решение задачи плохое? И какое решение, на ваш взгляд, хорошее?


              1. redfs
                15.03.2018 06:25

                Почему решение задачи плохое?
                Как вы сами признали, оно не является оптимальным. Почти по всем параметрам — время на разработку, пара тысяч зависимостей (в курсе истории о том, что было, когда одна из зависимостей сломалась и пропала из репо?), дальнейшее сопровождение и т.д. и т.п. Иными словами — вы простейшую, можно сказать — тестовую задачу решали, создавая себе максимальные сложности.

                Однако опять отмечу, что если вы все-таки решали другую задачу (самообучение), то задача решена хорошо.
                К сожалению, сейчас повсеместная беда с постановкой задачи, как таковой. Люди путают цели со средствами их достижения.

                И какое решение, на ваш взгляд, хорошее?

                Понимаете, как штука… Думаю, что это риторический вопрос с вашей стороны, потому что во первых, в комментах уже писали как минимум о нескольких, во вторых, стараюсь не участвовать в религиозных спорах.

                Ну как пример, вы пишите о подключаемых хедере и футере, что код шапки прописывать вручную в тысячах файлов — это ад…
                Могу сказать, что технология SSI известна больше 20 лет, но наверняка нарвусь на обвинение в «подходе динозавра».


                1. Harrix Автор
                  15.03.2018 08:29

                  Мда… Ожидал нормальная аргументацию.

                  Как вы сами признали, оно не является оптимальным.

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

                  время на разработку

                  По вашему любое решение с высоким порогом вхождения — это плохое решение?

                  пара тысяч зависимостей (в курсе истории о том, что было, когда одна из зависимостей сломалась и пропала из репо?), дальнейшее сопровождение

                  Есть такой файл. Называется package-lock.json, который хранит подробную информацию о всех пакетах с конкретными номерами версий. Так что я всегда, пока существует npm, смогу получить свой набор пакетов конкретных версий. Но даже если что-то пропадет, то мне достаточно заархивировать папочку node_modules и вообще беспокоиться не о чем.
                  А если произойдет какой-то капец в пакетах с многомиллионными загрузками, то проблема будет решена очень быстро.

                  К сожалению, сейчас повсеместная беда с постановкой задачи, как таковой. Люди путают цели со средствами их достижения.

                  И вот опять. «Цель — конечный результат, на который преднамеренно направлен процесс». В постановке не описаны конкретные инструменты, но они там могли быть на законных основаниях.

                  в комментах уже писали как минимум о нескольких, во вторых, стараюсь не участвовать в религиозных спорах.

                  Не надо сливаться. Мне нужен инструмент, который собирал бы HTML страницы, CSS собирал из SASS, Javascript собирал в один файл (желательно с поддержкой модулей), все это минифицировал, находил ошибки, шаблонизаторы HTML поддерживали условия (например, в шапке в меню можно было бы к пунктам меню ставить параметр active в зависимости от имени html страницы), желательно имелся быстрый способ обновления всех библиотек до последних версий и сборка на лету в статический(!) вариант, который мог бы работать локально. Предложите вариант.

                  Вроде бы насчитал три варианта, которые предлагали на замену. Один с сервером (не подходит под задачу создания статического сайта), один просто с блокнотом (так как я раньше так и делал, то вижу чем это плохо), один с использованием другого пакета из npm (этот вариант может быть даже очень хорошим), который обладает всеми теми же недостатками, которые вы приписали к моему варианту: высокий порог вхождения, зависимости и др.

                  Могу сказать, что технология SSI известна больше 20 лет

                  Server Side Includes — зачем вы предлагаете инструмент динамического сайта для статического сайта? Вы это серьезно? Нужна будет динамика — я возьму php или другой язык, куда лучше подходящий, чем SSI. Прочитайте название статьи. Требуется инструмент создания статического(!) сайта!


                  1. redfs
                    15.03.2018 08:41

                    Server Side Includes — зачем вы предлагаете инструмент динамического сайта для статического сайта? Вы это серьезно? Нужна будет динамика
                    Дальнейшие обсуждения не имеют смысла. Динамического? Нет, серьезно? Т.е. вы на самом деле считаете. что статику нельзя подключать через SSI? Знаете, прежде чем следовать моде, неплохо бы с основами разобраться.


                    1. Harrix Автор
                      15.03.2018 08:47

                      неплохо бы с основами разобраться.


                      Это какие-то старые основы. Пока я нахожу статьи 2011 или 2012 года, где рассказывается как SSI использовать на Apache. И статей как-то маловато. Тогда подскажите, пожалуйста, мне недалекому, который основ не знает, как с помощью SSI сгенерировать статические html файлы.


                      1. redfs
                        15.03.2018 09:10

                        подскажите, пожалуйста, мне недалекому, который основ не знает, как с помощью SSI сгенерировать статические html файлы
                        SSI не генерирует статические html файлы, а позволяет делать вставки в статические html файлы. Например, создаете статические header.html и footer.html. Потом можете создавать сколько угодно статических html файлов примерно следующего содержания:
                        <!--#include file="header.html" -->
                        <p>Моя статическая страница</p>
                        <!--#include file="footer.html" -->
                        


                        1. Harrix Автор
                          15.03.2018 09:20

                          SSI не генерирует статические html файлы


                          Если он не генерирует статические html страницы, то зачем мне он нужен? Правильно ли я понимаю, что есть сервер, который динамически подгружает include в html страницы по запросу пользователя? Так я про это и говорил, когда сказал «зачем вы предлагаете инструмент динамического сайта», а вы мне обвинили, что я основы не знаю. Сайт получается динамический!!! Ему нужен сервер для генерирования HTML страниц! Или я что-то не понимаю, и всё-таки можно его попросить сгенерировать как-то конкретные статические конечные html файлы.

                          Мне нужен инструмент статического(!) сайта! Чтобы я на выходе получил набор html файлов, которые я могу закинуть на тот же GitHub Pages или вообще открыть локально на компьютере. SSI для этого не подходит! Статический сайт! Не динамический!

                          В динамическом сайте HTML страницы генерируются по запросу пользователя на лету из исходников. И не важно являются ли исходники статическими файлами или нет!

                          В статическом сайте HTML страницы генерируются заранее, и на хостинге хранятся уже сгенерированные HTML страницы!


                          1. redfs
                            15.03.2018 11:29

                            Чтобы я на выходе получил набор html файлов, которые я могу… открыть локально на компьютере
                            Если без сервера, то (навскидку) я бы написал однострочник на bash минут за несколько. Это вообще не проблема — сгенерировать такие файлы.


                            1. Harrix Автор
                              15.03.2018 17:14

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

                              я бы написал однострочник на bash минут за несколько


                              Это будет точно однострочник? Напишите. И это будет именно настоящий однострочник, а не липовый, когда строчка длинная-предлинная? У меня код, который это делает в проекте, занимает чуть больше десяти строк. Но это уже несерьезно.

                              И да, даже если вы напишите скрипт на bash, то что изменится? Да, написать программу, которая заменяет содержимое некоторых строчек на содержимое других файлов во всех файлах папки — это легко везде. Только не понимаю, почему это делает мой вариант плохим.

                              Плюс к этому потом я предложу усложнить задачу: в меню шапки пункты меню, которые соответствуют названию файлов, должны иметь класс acitive. Или еще что-то. В моем решении в lodash шаблоне можно использовать любой js код.

                              Но даже, если вы покажите вариант (чего наверно не будет), когда bash осуществляет сборку html файлов, то это ничего не поменяет. Так как остаются задачи работы с SASS и js файлами. Сборка, минификация и др. Это как вы предлагаете сделать? Использовать другие инструменты? И завести целый зоопарк технологий? Или что-то другое?


                              1. redfs
                                15.03.2018 17:54

                                Плюс к этому потом я предложу усложнить задачу
                                :) Ну а потом, после потом… Нет уж, давайте я не буду тратить свое и ваше время, а просто соглашусь, что был неправ, и ваше решение совсем неплохое. если учитывать все нюансы.


                                1. Harrix Автор
                                  15.03.2018 17:57

                                  Пусть будет так.


                              1. justboris
                                15.03.2018 18:40

                                Вот есть вариант, если что: https://github.com/kidwm/node-ssi


                                В принципе, идея SSI норм, но видимо есть какие-то подводные камни, раз эта идея не стала популярной.


                                Возможно виной тому отсутствие эскейпа html и уязвимость к XSS. Может быть, просто не хватало возможностей (не увидел поддержки циклов).


                                Еще так и не нашел единого описания стандарта. Сложилось впечатление, что каждый веб-сервер (Apache, Jigsaw и т.п.)
                                поддерживает свой несовместимый набор команд


                      1. DexterHD
                        15.03.2018 20:00
                        -1

                        Купите лучше какую-нибудь книгу, лучше фундаментальную, касающуюся веб разработки в целом, истории вэба, истории развития браузеров и HTML.


                        1. Harrix Автор
                          15.03.2018 20:10

                          Зачем?


                          1. DexterHD
                            15.03.2018 21:06

                            Потому что изучение фундаментальных трудов это отличная инвестиция в будущее, если конечно вы хотите стать профессионалом в области разработки ПО. Конечно можно изучать все исключительно по статьям и Ютубам, но вряд ли это поможет сделать карьеру или найти работу на которой можно будет решать сложные и интересные задачи.


                            1. Zenitchik
                              15.03.2018 21:15

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


                              1. DexterHD
                                15.03.2018 21:30

                                Труды Танненбаума, «Архитектура компьютеров», «Операционные Системы», «Компьютерные Сети», это сугубо исторический интерес? Или может быть «Код» Петцольда представляет сугубо исторический интерес? А может быть Деннис Ритчи «Язык Си» ни кому не нужная историческая книжка? «Чистый код», «Программист прагматик», «Совершенный код», «Архитектура корпоративных приложений», или вот… Кнут «Искусство программирования», которая была написана пол века назад. Это все сугубо исторические книги? Я на 100% уверен что люди которые не читали хотя бы половину из перечисленного, понятия не имеют как писать программы, более того, в голове у них как правило каша и я регулярно с этим сталкиваюсь когда приходится нанимать людей на работу.

                                Любая фундаментальная литература не имеет срока давности и дает глубокие знания и понимание всего того что программист использует.
                                А читать книги по языкам программирования или не дай бог по Библиотекам, типа «Изучаем jQuery» или программируем на «React» — пустая трата времени.


                                1. Harrix Автор
                                  15.03.2018 22:27
                                  +1

                                  Какое отношение, например, «Совершенный код» относится к «книге, лучше фундаментальной, касающуюся веб разработки в целом, истории вэба, истории развития браузеров и HTML». Или тот же Кнут? А вам сказали именно насчет книг истории развития IT, про которые вы упомянули. А вы в ответ привели список отличных книг, но они про другое.

                                  А историю веба и так далее, как считаю, знаю достаточно. И читать еще какие-то дополнительные книги не хочется.


                                  1. DexterHD
                                    15.03.2018 22:56
                                    -2

                                    Это какие-то старые основы. Пока я нахожу статьи 2011 или 2012 года, где рассказывается как SSI использовать на Apache. И статей как-то маловато. Тогда подскажите, пожалуйста, мне недалекому, который основ не знает, как с помощью SSI сгенерировать статические html файлы.

                                    Достаточно хорошо чтобы писать такое? Ну ок. У вас кстати в постановке задачи первым стоит слово «Сайт», изучите чем «сайт» отличается от набора html страниц.


                                    1. Harrix Автор
                                      16.03.2018 00:42

                                      Достаточно хорошо чтобы писать такое?

                                      Да, я так считаю. Вы считаете, что каждый человек должен знать никем не используемую технологию? Таких технологий вагон и маленькая тележка.

                                      У вас кстати в постановке задачи первым стоит слово «Сайт», изучите чем «сайт» отличается от набора html страниц.

                                      Из-за того, что в статье опущено описания заливки файлов на хостинг никак не меняет сути.
                                      А про свои косяки с книгами вы решили умолчать… Ладно.


                                      1. DexterHD
                                        16.03.2018 01:12

                                        Да, я так считаю. Вы считаете, что каждый человек должен знать никем не используемую технологию? Таких технологий вагон и маленькая тележка.

                                        Я считаю что web-разработчик должен хорошо знать фундамент на котором стоит Web. А web стоит на целой пачке технологий некоторый из которых наложены одна на другую или являются развитием более старых вещей. И чтобы оптимально и правильно решать задачи нужно хотя бы иметь общее представление о всех них. Книги отсылающие к истории веба как нельзя лучше подходят для того чтобы вообще понять почему современный вэб такой какой он есть и где какие технологии стоит использовать, а где они избыточны или не нужны.


                                  1. DexterHD
                                    15.03.2018 23:04

                                    Ну или можно сменить постановку задачи и статью на: «Генерируем набор HTML страниц с помощью WebPack 4», тогда все вопросы и споры отпадут сами собой.
                                    Вот кстати неплохая цитатка про SSI, источник указывать не буду, вы и сами знаете:

                                    Static websites may still use server side includes (SSI) as an editing convenience, such as sharing a common menu bar across many pages. As the site's behaviour to the reader is still static, this is not considered a dynamic site.


                                    1. Harrix Автор
                                      16.03.2018 00:49

                                      Хм… Тут не смогу не согласиться и наоборот согласится. Например, в том же источнике ниже написано «Server-side dynamic pages are generated „on the fly“ by computer code that produces the HTML (CSS are responsible for appearance and thus, are static files).» Что как бы входит в противоречие с цитатой, которую вы привели. Но это уже чисто терминалогический спор: статический сайт определяется со стороны клиента или сервера.


                                      1. DexterHD
                                        16.03.2018 01:05

                                        Там 2 раздела. Первый называется Static website, второй Dynamic website. Я привел текст из первого раздела, вы приводите со второго. Нет ни каких противоречий. Просто прочитайте эти разделы и все станет на свои места.

                                        Вы утверждали что SSI сделает сайт динамическим, хотя это не так. И именно для этого я посоветовал ознакомится с фундаментальной литературой.

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


                                      1. redfs
                                        16.03.2018 07:58

                                        Но это уже чисто терминалогический спор: статический сайт определяется со стороны клиента или сервера
                                        Коллега, поясните, пожалуйста, вашу мысль — «статический сайт со стороны клиента»?
                                        Вам действительно надо привести в порядок терминологию, хотя бы для того, чтобы ваши читатели вас правильно понимали.


  1. beduin01
    13.03.2018 16:40

    Боже, в какое дно превратили Интернет любители NodeJS. Это не сайты, а уродцы какие-то. Тоже самое можно сделать в десять раз проще если выкинуть весь этот ужас.


    1. Harrix Автор
      13.03.2018 17:48

      Это не сайты, а уродцы какие-то.

      Уродство с точки зрения сборки или с точки зрения получившегося результата? Если второе, то что там уродского? Обычныt Bootstrap страницы.

      Тоже самое можно сделать в десять раз проще если выкинуть весь этот ужас.

      Специально в статье приведена постановка задачи. Скажите как её можно решить в десять раз проще. Честно, буду очень признателен.


      1. beduin01
        13.03.2018 18:00

        С точки зрения процесса. Нафиг NodeJS нужен для сайтов я так и не понял.
        Типичный мой проект:
        1. Сгенерированные статические роутеры через vibed c шаблонизатором pug/diet
        2. Динамические части на vuejs подгружаемые через http-vue
        3. css по вкусу, которую можно прям в компонентах vue разместить.

        В итоге проект весит сотни килобайт (исходники). Переносится с компа на комп копи-пастом. Никаких мучительных конфигураций веб-пака и развертывания NodeJS.


        1. Harrix Автор
          13.03.2018 18:11

          Смутно представляю эти технологии, так что задам несколько вопросов.
          Правильно ли я понимаю, что это получается скорее web приложение, чем обычные web страницы, где html код можно посмотреть просто в html файлах?
          Как я понимаю, вначале были прописаны эти исходники, настроены и всё такое. А чем тогда от предложенного способа отличается? Мне нужно будет в другом проекте написать только npm i и вся настроенная система появится опять.
          Где-нибудь можно посмотреть на пример такого проекта? Возможно от webpack перейду к vue.js.


          1. beduin01
            13.03.2018 19:01

            Нет получаются очень удобные html-страницы. Которые генерятся на сервере т.е. их видит поисковик. Всякие модные интерактивные компоненты можно оформлять именно как веб-компоненты и подгружать в нужные места.
            Тоесть проблем с индексацией не будет. Страницы все открываются пулей.
            pug шаблон позволяет описать каркас сайта один раз и потом просто цеплять к нему нужные блоки.
            Пример кину в личку.


        1. justboris
          14.03.2018 02:14

          vibed — это вы имеете в виду vibe-d, веб-сервер на D?


          1. beduin01
            14.03.2018 10:48

            Да, именно


            1. justboris
              14.03.2018 11:21
              +1

              Так это же веб-сервер, его запускать где-то надо.


              Статья про принципиально другой подход. Статический сайт собирается из исходников скриптом и получается несколько html-файлов. Эти файлы загружаются на любое файлохранилище (surge, netlify или Github pages). Затем прикручиваете кастомный домен, и сайт готов. Поддерживать запущенный сервер не надо вообще.


      1. DexterHD
        13.03.2018 19:57

        Открыть любой текстовый редактор и решить. В 10 раз проще и главное быстрее. Постановка задачи на самом деле, это первое предложение, а второе предложение:

        Необходимо написать проект, который бы собирал наш сайт из исходников:

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


        1. Harrix Автор
          13.03.2018 20:11
          +1

          Открыть любой текстовый редактор и решить.


          Ввиду того, что раньше так и делал, то могу оценить насколько эти два варианта. Во-первых, без SCSS работу с CSS я сейчас вообще не представляю. Повышает удобство работы во много раз. Можно найти программы, которые позволяют работать с SASS без node.js (например, Koala), но внутри них также стоят настроенные бандлеры. Во-вторых, работа с js с модулями и компоновкой в один файл также сильно повышает удобство работы (но не так сильно). В-третьих, шаблонизаторы с возможностью написания условий, циклов — так это вообще красота. А вручную прописывать один и тот же код шапки, например, в сотнях html файлах — это ад.


  1. vvadzim
    13.03.2018 16:58

    А такой инструмент parceljs.org рассматривали?
    Для подобных задач вроде как подходит.


    1. Harrix Автор
      13.03.2018 17:50

      Опа… Надо будет на него глянуть. В декабре было 8725 звезд на гихабе, а сейчас 20338! Правда число установок в node.js в месяц у webpack пока еще сильно больше: 13 188 708 против 35 097. Но обязательно посмотрю на этого зверя.


      1. vvadzim
        13.03.2018 19:27
        +1

        Webpack сильно врос в экосистему — те же create-react-app/create-react-native-app.
        Webpack появился и обошел browserify как ответ на необходимость экспериментировать и настраивать.
        А parceljs появился когда стэк устаканился и с конфигами наигрались.
        Кстати, у того же browserify все ещё 3,5 млн загрузок. Раз вас это радует)


  1. Odrin
    14.03.2018 12:13

    И если добавить стили библиотеки в наш style.scss, то file-loader будет искать картинки библиотеки lightgallery в моей папке src/img, а не там, где они находятся. И побороть я это не смог.

    Если я правильно понял суть проблемы, то она решается с помощью resolve-url-loader


  1. maolo
    14.03.2018 22:10

    Как раз в процессе переноса сборки с gulp'а на webppack — так что Ваша статья в руку, есть то, с чем я еще не разобрался.


    И если добавить стили библиотеки в наш style.scss, то file-loader будет искать картинки библиотеки lightgallery в моей папке src/img, а не там, где они находятся. И побороть я это не смог.

    Опция exclude не поможет, примерно как здесь указано — https://stackoverflow.com/questions/44211666/how-to-exclude-bootstrap-files-when-css-modules-is-enabled ?


    Обратите внимание на то, что в точках входа entryмы добавили новый входной файл style.scss

    Кстати, если в output указать не конкретное имя, а чанки, напр.,


    filename: "js/[name].js",

    то в папке dist/js появится style.js… пустой) (ну, не совсем пустой — там будет вебпаковаская обертка, но по сути, ничего не делающая, поскольку стили извлечены extract плагином)


    Поэтому для итоговой сборки рекомендую использовать не команду *npm run build, а команду npm run build-and-beautify.

    В npm можно указывать команды с префиксами "pre" и "post", которые запустяться, соотвественно, до и после основной команды, т.е. вот это:


    "scripts": {
        "build-and-beautify": "webpack --mode production && html dist/*.html --indent-size 2",
        "beautify": "html dist/*.html --indent-size 2"
      },

    можно записать так:


    "scripts": {
        "build": "webpack --mode production && html dist/*.html --indent-size 2",
        "postbuild": "html dist/*.html --indent-size 2"
      },

    команда postbuild запуститься автоматически после выполнения build


    1. maolo
      14.03.2018 22:18

      Еще очень рекомендую эту книгу о вебпак — SurviveJS — Webpack
      И курс Ильи Кантора (хоть и 2015 г., но все равно полезный в плане понимация настройки Webpack) — Скринкаст по Webpack


    1. maolo
      15.03.2018 00:37

      поправка к "build-and-beautify":


      "scripts": {
          "beautify": "html dist/*.html --indent-size 2",
          "build": "webpack --mode production",
          "postbuild": "npm run beautify"
        },


  1. maolo
    15.03.2018 00:36

    * промах


  1. Alter2
    15.03.2018 01:17
    -1

    Мда, простые статичные сайты уже не те.

    В чем преимущества такого подхода вместо того чтобы просто выложить файлы на сервер?


    1. Harrix Автор
      15.03.2018 08:50

      Прежде чем выложить файлы, их нужно как-то подготовить. Например, формируется документация в виде HTML страниц. Страниц таких больше сотни. И допустим, я писал их вручную. И потом мне в шапке каждой страницы нужно что-то поменять. Как?


  1. koutsenko
    15.03.2018 23:17

    Интересно, можно ли использовать JSX в отрыве от реакта. Как шаблонизатор. В итоге, сочетая с описанной в статье конфигурацией, в итоге можно посадить дизайнера-верстальщика делать макет, а потом скопировать верстку в реальный проект (естесственно с некоторыми правками — другим разбиением на компоненты, с заточками под условное отображение и т.п.).


    1. DexterHD
      15.03.2018 23:30

      JSX is an XML-like syntax extension to ECMAScript without any defined semantics.
      This specification does not attempt to comply with any XML or HTML specification. JSX is designed as an ECMAScript feature and the similarity to XML is only for familiarity.