Dzisiaj będzie krótko. Usuniemy nadmiarowe style z Bootstrap. Do tego zadania potrzebne nam będzie webpack, plugin purgecss-webpack-plugin, a za template posłuży nam pug oraz html.
Do testów użyłem dwóch przykładów ze strony bootstrapa, album oraz sign-in. Tak aby móc porównać czy działanie jest identyczne w wersji html i pug.
Najpierw tworzymy package.js
yarn init -y
Następnie dodamy wszystkie pluginy:
yarn add -D @babel/core @babel/preset-env autoprefixer babel-loader clean-webpack-plugin core-js cross-env css-loader cssnano html-webpack-plugin mini-css-extract-plugin node-sass postcss-cli postcss-loader pug pug-loader purgecss-webpack-plugin sass-loader style-loader terser-webpack-plugin webpack webpack-cli webpack-dev-server
W związku z tym że nasz przykład jest bardziej rozbudowany niże to co możemy zobaczyć w oficjalnej dokumentacji PurgeCSS to trochę tych pluginów jest 😉 Nie będę ich opisywał jedynie napiszę że są one między innymi do optymalizacji styli, konwersji e6 do es5, itd. Najważniejszy plugin to purgecss-webpack-plugin on odpowiada za usuwanie nadmiarowego css.
Użycie pluginu
Użycie jego jest bardzo proste, wystarczy tylko do webpacka dodać"
const glob = require('glob');
const PurgecssPlugin = require('purgecss-webpack-plugin');
// ścieżka do naszych plików html oraz template
const PATHS = {
src: path.join(__dirname, 'src')
}
A w sekcji z pluginami po prostu dodajemy:
plugins: [
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true })
})
...
]
Plugin ten sprawdza każdy plik w naszym przypadku w cały folderze src i szuka klas które są wykorzystywane.
Cała struktura src wygląda tak jak poniżej:
.
├── scss
│ ├── footer.scss
│ └── signin.scss
├── template-html
│ ├── form.html
│ └── index.html
├── template-pug
│ ├── form.pug
│ └── index.pug
├── bootstrap.min.css
├── form.js
└── index.js
Teraz należy w pliku package.json umieściłem sekcję za pomocą której można sterować jaka wersja będzie kompilowana. Tak jak na wstępie napisałem mamy dwie wersje html oraz pug.
"scripts": {
"devhtml": "cross-env TYPE='html' webpack-dev-server --config webpack.config.js --mode development --open",
"devpug": "cross-env TYPE='pug' webpack-dev-server --config webpack.config.js --mode development --open",
"html": "cross-env TYPE='html' webpack --config webpack.config.js --mode production ",
"pug": "cross-env TYPE='pug' webpack --config webpack.config.js --mode production"
}
A tak wygląda cały webpack
const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const PurgecssPlugin = require('purgecss-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const type = process.env.TYPE;
const PATHS = {
src: path.join(__dirname, 'src')
}
const ENTRY = {
index: "./src/index.js",
form: "./src/form.js"
}
const prodPlugin = (plugin, argv) => {
return argv.mode === 'production' ? plugin : () => { };
}
const configureStyleLoader = mode => {
return {
test: /\.(css|sass|scss)$/,
use: [
mode === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
}
],
};
};
// Configure Clean Webpack
const configureCleanWebpack = () => {
return {
dry: false,
verbose: false
};
};
// Config Html
const entryHtmlPlugins = Object.keys(ENTRY).map(entryName => {
return new HtmlWebpackPlugin({
filename: `${entryName}.html`,
template: `./src/template-${type}/${entryName}.${type}`,
chunks: [entryName]
});
});
// Configure Terser
const configureTerser = () => {
return {
cache: true,
parallel: true,
sourceMap: true,
};
};
// Configure Pug Loader
const configurePugLoader = () => {
return {
test: /\.pug$/,
loader: 'pug-loader',
options: {
pretty: true,
self: true,
},
};
};
// Configure Optimization
const configureOptimization = () => {
return {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
},
styles: {
name: 'styles',
test: /\.s?css$/,
chunks: 'all',
minChunks: 2,
enforce: true,
},
},
},
minimizer: [new TerserPlugin(configureTerser())],
};
};
module.exports = (env, argv) => {
return {
mode: argv.mode === "production" ? "production" : "development",
entry: ENTRY,
output: {
filename: "vendor/js/[name].js",
path: path.resolve(__dirname, `dist-${type}`),
chunkFilename: 'vendor/js/[name].js'
},
optimization: configureOptimization(),
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
configureStyleLoader(argv.mode),
configurePugLoader()
]
},
plugins: [
prodPlugin(new CleanWebpackPlugin(configureCleanWebpack()), argv),
new MiniCssExtractPlugin({
filename: "vendor/css/[name].css"
}),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true })
}),
].concat(entryHtmlPlugins)
}
};
Podsumowanie
PurgeCSS to nie tylko purgecss-webpack-plugin ale także plugin do Gulp, Grunt, czy Gatsby. Zainteresowanych odsyłam do strony purgecss.com
Pod tym adresem znajduje się cały kod. Samemu można go przeanalizować.