#3 Сборщик модулей webpack. Разбираемся с css. Часть 3.

poster
В этом уроке мы разберем как подключить css файлы к модулю, или как генерировать отдельный css файл на основе используемых модулей.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

Всем привет! Сегодня мы с вами продолжаем изучать webpack. А именно - будем разбираться со стилями и с тем, как сделать стили модульными.

Для начала, давайте установим плагины

npm install style-loader --save

Этот плагин нам понадобится для того, чтобы webpack мог валидно работать с css. Второй плагин, который нам понадобится это css-loader

npm install css-loader --save

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

Теперь нам необходимо добавить еще один loader в наш конфиг

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    resolve: {
        modulesDirectories: ['node_modules']
    },
    module: {
        loaders: [
            {
                test: /\.js/,
                loader: 'babel',
                exclude: /(node_modules|bower_components)/
            },
            {
                test: /\.css$/,
                loader: 'style!css'
            }
        ]
    }
};

В test мы пишем регулярку для того, чтобы webpack парсил css файлы. Поставим $, так как это будет конец выражения, хотя это, впринципе, не обязательно. И добавим loader: 'style!css'. Мы также могли бы полностью написать style-loader|css-loader, но webpack принимает и сокращенный вариант записи.

Теперь, давайте создадим файл main.css и запишем какие-то стили, например, в body

body {
    background: grey;
};

И, теперь подключим его в наш main.js

import '.main.css';

import _ from 'lodash';

console.log(_.isEqual(1, 2));

var obj = {
    field: 111,
    someFn() {
        console.log('someFn');
    }
};

obj.someFn();

Теперь, если пропишем в консоли

webpack

и посмотрим в браузер, то увидим что наш стиль применился и страница стала серой.

Теперь давайте поинспектим элементы. Как мы можем видеть - у нас в head добавился новый инлайновый style в котором прописан наш стиль для body. Это говорит о том, что все стили которые мы добавляем через импорты css - берутся из файлов css и вставляются на страницу инлайново. Это не всегда удобно, поэтому webpack позволяет также генерировать отдельный css файл и просто подключать его к index.html.

Также вы можете спросить: "А как же организовывать css, если, например, мы можем задать у одного модуля class для body - background: grey, а у другого - background: red и, этим самым, переопределить его?". Чтобы такого не возникло - я рекомендую вам использовать такой подход разработки в css как БЭМ методология. Это поможет вам делать код модульным и также это отлично сочетается с модульностью webpack.

Теперь давайте создадим отдельный css файл. Для этого нам нужно сделать несколько вещей. Во-первых, нам нужно поставить плагин

npm i extract-text-webpack-plugin --save

Данный плагин нам необходим для того, чтобы мы весь наш css смогли поместить в один файл bundle.css.

Теперь в файле конфига в самом верху пропишем

var ExtractTextPlugin = require('extract-text-webpack-plugin');

Теперь, заменим один из лоадеров, который мы описали ранее для файлов css на loader: ExtractTextPlugin.extract() и в качестве параметров передадим style-loader и css-loader

var ExtractTextPlugin = require ('extract-text-webpack-plugin');

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    resolve: {
        modulesDirectories: ['node_modules']
    },
    module: {
        loaders: [
            {
                test: /\.js/,
                loader: 'babel',
                exclude: /(node_modules|bower_components)/
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
            }
        ]
    }
};

Теперь, все что нам нужно - подключить сюда plugins, который будет представлять из себя дополнительный массив плагинов, которые мы хотим подключить к нашему webpack

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    resolve: {
        modulesDirectories: ['node_modules']
    },
    module: {
        loaders: [
            {
                test: /\.js/,
                loader: 'babel',
                exclude: /(node_modules|bower_components)/
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin('bundle.css');
    ]
};

bundle.css - название нашего css файла, который будет автоматически генерироваться.

Запускаем в консоли

webpack

и как мы видим - у нас создался не только файл bundle.js, но и файл bundle.css. Если мы зайдем в файл bundle.css, то увидим, что он был сгенерирован из нашего файла main.css. Причем, что самое классное, если вы запустите в консоли

webpack --watch

и будете менять какой-то файл, например, внесем изменения в main.css

body {
    background: red;
};

то мы увидим в консоли, что оба файла сразу же перекомпилировались. И, если мы посмотрим в браузер сейчас, то увидим, что стили у нас не применились, так как не подключен css файл в index.html. Давайте его подключим

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="bundleƒ.css">
</head>
<body>
    ssss

    <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
</body>
</html>

Теперь, при обновлении браузера, мы увидим, что все стили подхватываются и цвет body стал красным. Мы можем поменять его обратно на grey. При этом вотчер у нас отработал и при обновлении страницы - мы увидим изменения.

Как мы видим, webpack легко работает с css и позволяет нам использовать для этого два подхода: инлайново добавлять стили, или генерировать файл и уже непосредственно с ним работать. Это достаточно удобно и, как мы видим, например, раннеры такие как grunt или gulp, при использовании webpack - особо не нужны, так как webpack вполне самодостаточен.

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
vlad
8 лет назад
доброго времени суток bundle.js - собирается bundle.css - нет в чем может быть причина? var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, resolve: { modulesDirectories: ['node_modules'] }, module: { loaders: [ { test: /\.js/, loader: 'babel', exclude: /(node_modules|bower_components)/ }, { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }, { test: /\.hbs/, loader: 'handlebars-loader', exclude: /(node_modules|bower_components)/ } ] }, plugins: [ new ExtractTextPlugin("bundle.css") ] };
monsterlessons
8 лет назад
Так сложно сказать. Я ошибки в конфиге не вижу.
Aleksandr Polyakh
9 лет назад
Доброе время суток. Не могу вынести стили из всех компонентов при сборке 'production', что не так делаю? Доброе время суток. При сборке 'production', стили выносятся только те, которые подключаю в index.js(вход в приложение). Сделал всё как описано в оф. документации к 'Extract Text Plugin', { allChunks: true }. webpack.config.js: https://codepen.io/PolyakhAlex/pen/aLrxVN?editors=0010; В самому низу указал настройку под 'prod' которую вынес в отдельный модуль. Спасибо за помощь!
monsterlessons
9 лет назад
Я отвечаю только на комментарии относящиеся непосредственно к уроку, или близко к нему, и не даю консультаций к коду не связанному с уроками. Спасибо за понимание!
Aleksandr Polyakh
9 лет назад
Доброе время суток, подскажите пожалуйста. Когда прописываю loader: 'sourceMap' для CSS develop: loader: `style!css?${!isProd ? 'sourceMap' : null}!sass` Есть проблема, всё стили импортируються в один файл index.scss, в браузере показывает, что стили определенного компонента подключены относительно основного файла стилей index.scss, как сделать так, чтобы было видно с какого файла мы импортируем стили для определенного компонента? Спасибо!
monsterlessons
9 лет назад
Добрый день. Посмотрите в сторону css sourcemaps.
Aleksandr Polyakh
9 лет назад
Спасибо, не думал, что так долго необходимо изучать webpack чтобы сделать хорошую сборку)
monsterlessons
9 лет назад
На самом деле это далеко не так просто. Так как существует много способов сделать одно и тоже и не всегда даже в документации есть готовые решения. И приходится использовать дополнительные библиотеки и плагины, которые очень часто работают непредсказуемо.
Aleksandr Polyakh
9 лет назад
Спасибо, вам но у меня ничего не выходить, подскажите пожалуйста что не так делаю? Ссылка на config
monsterlessons
9 лет назад
Попробуйте подебажить, почитать документацию, посмотреть примеры других людей на гитхабе. По конфигу сложно сразу решить проблему и указать ошибку.
Aleksandr Polyakh
9 лет назад
Спасибо, прежеде чем задавать суда вопрос всегда пытаюсь сам решить проблему, сделал так как Вы сказали получил ошибку: const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = function (paths) { return { module: { rules: [ { test: /\.scss$/, include: paths, use: ExtractTextPlugin.extract({ publicPath: '../', fallback: 'style-loader', use: ['css-loader', 'sass-loader'], }), }, { test: /\.css$/, include: paths, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader", options: { minimize: true } }), }, ], }, plugins: [ new ExtractTextPlugin('./css/[name].[hash:4].css'), ], }; }; Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. - configuration.module.rules[2].use should be one of these: non-empty string | function | object { loader?, options?, query? } | function | [non-empty string | function | object { loader?, options?, query? }] Details: * configuration.module.rules[2].use should be a string. * configuration.module.rules[2].use should be an instance of function. * configuration.module.rules[2].use should be an object. * configuration.module.rules[2].use should be one of these: non-empty string | function | object { loader?, options?, query? } * configuration.module.rules[2].use should be an instance of function. * configuration.module.rules[2].use[1] should be a string. * configuration.module.rules[2].use[1] should be an instance of function. * configuration.module.rules[2].use[1] has an unknown property 'use'. These properties are valid: object { loader?, options?, query? } * configuration.module.rules[2].use[1] should be one of these: non-empty string | function | object { loader?, options?, query? } error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
monsterlessons
9 лет назад
Опции нужно передавать не в ExtractTextPlugin, а в loader. rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: { loader: 'css-loader', options: { minimize: true } } }) } ] },
Aleksandr Polyakh
9 лет назад
Спасибо, немного не корректно спросил. По коду который Вы прислали в какой строке, мы указываем, что необходимо сжать CSS?
monsterlessons
9 лет назад
В разделе rules мы указываем что мы хотим на файлы .css использовать ExtractTextPlugin и внутри указываем через какие загрузчики мы хотим пропустить файл. В данном случае style и css. Для минификации вы можете указать { loader: "css-loader", options: { minimize: true } }
Aleksandr Polyakh
9 лет назад
Спасибо за столь быстрый ответ, в какой момент CSS, будет минифицирован?
monsterlessons
9 лет назад
В момент запуска команды webpackа.
Aleksandr Polyakh
9 лет назад
Доброе время суток, подскажите пожалуйста как для production сжать CSS? Использую extract-text-plugin, версия webpack 2.7.0, сам не смог разобраться (
monsterlessons
9 лет назад
Добрый вечер. В вашем production вебпак конфиге указываете const ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { module: { rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" }) } ] }, plugins: [ new ExtractTextPlugin("styles.css"), ] } и весь css, который вы импортируете в js файлах собирается в styles.css файл.
Konstant K
9 лет назад
Спасибо за объяснения! Подскажите, как отключать работающий watch? какие еще другие полезные команды для работы с webpack существуют?
monsterlessons
9 лет назад
Отключать любой watch ctrl/command + c . И это не только webpack касается. Собирать webpack в production режиме -p Девелопмент мод (с debug, sourcemaps, логами) -d