Как подружить webpack и semantic-ui

Предыстория: раньше я жил на jspm и systemjs, но меня подкупила быстрота webpack-а и его возможность горячей замены. Посему я приступил к переезду. TLDR Source code

Начнем с того, что установим jquery и semantic-ui

npm install --save jquery@2.1.4 semantic-ui-css

Semantic-ui-css это тот же semantic-ui, но который не надо собирать (он просто с дефолтной темой). jquery нужен 2-ой версии, ибо с 3-ей семантик местами не дружит (может быть ситуация уже поменялась).

Установим также и то, чем мы это всё будем собирать и показывать

npm install --save-dev webpack babel-core babel-loader babel-preset-es2015 http-server

Babel здесь лишь потому что я привык к ES2015, но раз он есть, то грех не добавить .babelrc

{
"presets": ["es2015"],
}

Настроим webpack

var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, "build"),
filename: 'app.bundle.js'
},
resolve: {
alias: {
'semantic-ui': path.join(__dirname, "node_modules", "semantic-ui-css", "semantic.js"),
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'babel-loader'
}]
}
};

Тут нужен alias на semantic-ui c указанием конкретного файла (а не ‘semantic-ui’: ‘semantic-ui-css’) потому в package.json у semantic-ui-css нет поля main, я уже создал issue для этого https://github.com/Semantic-Org/Semantic-UI-CSS/issues/21

Создадим нашу точку входа, index.js

import $ from 'jquery'
import semantic from 'semantic-ui'
$('#dropdown').dropdown()

И сделаем маленькую страничку чтобы это все показать, index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="node_modules\semantic-ui-css\semantic.min.css">
</head>
<body>
<div id="dropdown" class="ui selection dropdown">
<input type="hidden" name="gender">
<i class="dropdown icon"></i>
<div class="default text">Gender</div>
<div class="menu">
<div class="item" data-value="1">Male</div>
<div class="item" data-value="0">Female</div>
</div>
</div>
  <script src="build/app.bundle.js"></script>
</body>
</html>

Добавим скрипты в package.json

"scripts": {
"build": "./node_modules/.bin/webpack",
"web": "./node_modules/.bin/http-server",
"start": "npm run build && npm run web"
}

Запустим все это с помощью npm start и… увидим в консоли браузера вот это: Uncaught ReferenceError: jQuery is not defined. Проблема в том что semantic-у для инициализации требуется глобальная jQuery, а инициализация происходит не в момент import-а, а при первом проходе интерпретатора js по app.bundle.js. И как быть? На помощь нам приходит ProvidePlugin (он встроен в webpack и дополнительных пакетов тянуть не надо). Дополним конфигурацию webpack

plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]

Попробуем npm start еще раз… все работает!