From a318386602b22df99b2adc322b636b225d42cbcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Fri, 19 Sep 2025 13:49:11 +0000 Subject: [PATCH 1/8] Teste einen Gulp Task, der SCSS mit Webpack kompiliert --- package.json | 3 ++ tasks/stylepack.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 tasks/stylepack.js diff --git a/package.json b/package.json index ea1b1c2..28c5a59 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "babel-loader": "^8.2.2", "browser-sync": "^2.26.7", "browserslist-config-webfactory": "^1.0.0", + "css-loader": "^7.1.2", "dotenv": "^10.0.0", "fancy-log": "^1.3.3", "gulp": "^4.0.0", @@ -22,10 +23,12 @@ "gulp-stylelint": "^13.0.0", "gulp-svgmin": "^4.1.0", "gulp-terser": "^2.0.1", + "mini-css-extract-plugin": "^2.9.4", "minimist": "^1.2.0", "postcss": "^8.0.9", "postcss-preset-env": "^9.3.0", "postcss-url": "^10.1.3", + "sass-loader": "^16.0.5", "stylelint": "^14.1.0", "stylelint-config-sass-guidelines": "^9.0.1", "stylelint-order": "^5.0.0", diff --git a/tasks/stylepack.js b/tasks/stylepack.js new file mode 100644 index 0000000..c011419 --- /dev/null +++ b/tasks/stylepack.js @@ -0,0 +1,69 @@ +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); + +function stylepack(gulp, $, config) { + let entrypoints = {}; + + config.styles.files.map((file) => { + entrypoints[file.name] = { + import: `/${config.webdir}/${file.files}`, + filename: file.destDir ? `webpack-tmp/${file.destDir}/[name]` : 'webpack-tmp/[name]' + }; + }); + + return gulp.src(config.webdir + '/**/scss/**/*.scss') + .pipe($.webpackStream({ + entry: entrypoints, + // output: { + // filename: `[name]`, + // }, + resolve: { + mainFields: ['browser', 'module', 'main'], + }, + module: { + rules: [ + { + test: /\.s[ac]ss$/i, + use: [ + { + loader: MiniCssExtractPlugin.loader, + options: {}, + }, + { + loader: 'css-loader', + options: { + sourceMap: true, + } + }, + { + loader: 'sass-loader', + options: { + implementation: 'sass-embedded', + api: 'modern', + sourceMap: true, + sassOptions: { + // importers: new NodePackageImporter(), + loadPaths: config.styles.includePaths ? config.styles.includePaths : [config.npmdir] + }, + }, + }, + ], + }, + ], + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: "css/[name]", + }), + ], + mode: config.development && $.argv.prod !== true ? 'development' : 'production', + devtool: $.argv.debug === true ? 'source-map' : false, + stats: { + preset: 'normal', + timings: true + }, + }, $.webpack)) + .pipe(gulp.dest(config.webdir)) + .pipe($.browserSync.reload({ stream: true })); +} + +exports.stylepack = stylepack; From bb97a32a93b1ea8a9efda66bf0fbefa8eef08af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Thu, 25 Sep 2025 12:42:15 +0000 Subject: [PATCH 2/8] Add asset url rebasing via Webpack's resolve-url-loader --- package.json | 1 + tasks/stylepack.js | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/package.json b/package.json index 28c5a59..b46a75e 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "postcss": "^8.0.9", "postcss-preset-env": "^9.3.0", "postcss-url": "^10.1.3", + "resolve-url-loader": "^5.0.0", "sass-loader": "^16.0.5", "stylelint": "^14.1.0", "stylelint-config-sass-guidelines": "^9.0.1", diff --git a/tasks/stylepack.js b/tasks/stylepack.js index c011419..aa89d9e 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -21,6 +21,13 @@ function stylepack(gulp, $, config) { }, module: { rules: [ + { + test: /\.(png|jpe?g|gif|svg|webp|avif)$/i, + type: 'asset/resource', + generator: { + filename: 'img/[name].[hash][ext]' + } + }, { test: /\.s[ac]ss$/i, use: [ @@ -34,6 +41,12 @@ function stylepack(gulp, $, config) { sourceMap: true, } }, + { + loader: 'resolve-url-loader', + options: { + debug: true, + } + }, { loader: 'sass-loader', options: { From e1b6f13cc5a37c79c80b2e9f302ac92b19977f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Fri, 26 Sep 2025 16:09:18 +0000 Subject: [PATCH 3/8] Add postcss-loader for postcss-preset-env --- package.json | 1 + tasks/stylepack.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/package.json b/package.json index b46a75e..1cb17fd 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "mini-css-extract-plugin": "^2.9.4", "minimist": "^1.2.0", "postcss": "^8.0.9", + "postcss-loader": "^8.2.0", "postcss-preset-env": "^9.3.0", "postcss-url": "^10.1.3", "resolve-url-loader": "^5.0.0", diff --git a/tasks/stylepack.js b/tasks/stylepack.js index aa89d9e..658c736 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -47,6 +47,18 @@ function stylepack(gulp, $, config) { debug: true, } }, + { + loader: "postcss-loader", + options: { + postcssOptions: { + plugins: [ + [ + "postcss-preset-env", + ], + ], + }, + }, + }, { loader: 'sass-loader', options: { From d65115f2b9d539054c93ecfdfbe6d0f3e6e49270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Fri, 26 Sep 2025 16:16:19 +0000 Subject: [PATCH 4/8] Add sourcemap (needed for resolve-url-loader) --- tasks/stylepack.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tasks/stylepack.js b/tasks/stylepack.js index 658c736..f485c20 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -50,6 +50,7 @@ function stylepack(gulp, $, config) { { loader: "postcss-loader", options: { + sourceMap: true, postcssOptions: { plugins: [ [ From 2bfa731f3fc908e80a9b34592f1bbe8d2010908e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Fri, 26 Sep 2025 16:52:27 +0000 Subject: [PATCH 5/8] Try first iteration of postcss-purgecss --- tasks/stylepack.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tasks/stylepack.js b/tasks/stylepack.js index f485c20..bd4504a 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -1,4 +1,22 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const postcssPurgecss = require("@fullhuman/postcss-purgecss")({ + content: [ + './src/**/*.html', + ], + extractors: [ + { + extractor: utilityCssExtractor, + extensions: ['php', 'twig', 'js', 'svg'] + } + ], + safelist: [/^is-/, /^js-/] // adapt to classes you must keep +}); + +// This custom extractor will also match selectors that contain +// special chars like "_", ".", ":", "\" and "@" +function utilityCssExtractor(content) { + return content.match(/[a-zA-Z0-9-_.:@\/]+/g) +} function stylepack(gulp, $, config) { let entrypoints = {}; @@ -53,9 +71,8 @@ function stylepack(gulp, $, config) { sourceMap: true, postcssOptions: { plugins: [ - [ - "postcss-preset-env", - ], + ["postcss-preset-env"], + postcssPurgecss, ], }, }, From c3dd58cb727c314b198ec0bd7ad21c36d21b71d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Mon, 29 Sep 2025 15:12:14 +0000 Subject: [PATCH 6/8] Enable a separate config per entry file for Webpack plugins --- tasks/stylepack.js | 69 +++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/tasks/stylepack.js b/tasks/stylepack.js index bd4504a..533151a 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -1,16 +1,9 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const postcssPurgecss = require("@fullhuman/postcss-purgecss")({ - content: [ - './src/**/*.html', - ], - extractors: [ - { - extractor: utilityCssExtractor, - extensions: ['php', 'twig', 'js', 'svg'] - } - ], - safelist: [/^is-/, /^js-/] // adapt to classes you must keep -}); +const postcssPurgecss = require("@fullhuman/postcss-purgecss"); +const argv = require('minimist')(process.argv.slice(2)); +const webpackStream = require('webpack-stream'); +const mergeStream = require('merge-stream'); +const path = require('path'); // This custom extractor will also match selectors that contain // special chars like "_", ".", ":", "\" and "@" @@ -19,21 +12,22 @@ function utilityCssExtractor(content) { } function stylepack(gulp, $, config) { - let entrypoints = {}; - config.styles.files.map((file) => { - entrypoints[file.name] = { - import: `/${config.webdir}/${file.files}`, - filename: file.destDir ? `webpack-tmp/${file.destDir}/[name]` : 'webpack-tmp/[name]' - }; - }); + const streams = config.styles.files.map((file) => { + let purgeCssConfig = config.styles.purgeCss; + + // Check for CLI flags/args + let purgeCssDisabled = argv.purgecss === false; - return gulp.src(config.webdir + '/**/scss/**/*.scss') - .pipe($.webpackStream({ - entry: entrypoints, - // output: { - // filename: `[name]`, - // }, + // Determine if PurgeCSS should run + let purgeCss = purgeCssConfig && !purgeCssDisabled; + + const webpackConfig = { + entry: `/${config.webdir}/${file.files}`, + output: { + // path: path.resolve(__dirname, 'webpack-tmp', file.destDir || ''), + filename: `webpack-tmp/${file.name}`, + }, resolve: { mainFields: ['browser', 'module', 'main'], }, @@ -51,7 +45,6 @@ function stylepack(gulp, $, config) { use: [ { loader: MiniCssExtractPlugin.loader, - options: {}, }, { loader: 'css-loader', @@ -72,8 +65,17 @@ function stylepack(gulp, $, config) { postcssOptions: { plugins: [ ["postcss-preset-env"], - postcssPurgecss, - ], + purgeCss ? postcssPurgecss({ + content: purgeCssConfig.content, + extractors: [ + { + extractor: utilityCssExtractor, + extensions: ['php', 'twig', 'js', 'svg'] + } + ], + safelist: purgeCssConfig.safelist, + }) : false, + ].filter(Boolean), }, }, }, @@ -95,7 +97,7 @@ function stylepack(gulp, $, config) { }, plugins: [ new MiniCssExtractPlugin({ - filename: "css/[name]", + filename: `${file.destDir}/${file.name}`, }), ], mode: config.development && $.argv.prod !== true ? 'development' : 'production', @@ -104,8 +106,13 @@ function stylepack(gulp, $, config) { preset: 'normal', timings: true }, - }, $.webpack)) - .pipe(gulp.dest(config.webdir)) + }; + + return webpackStream(webpackConfig) + .pipe(gulp.dest(path.join(config.webdir))); + }); + + return mergeStream(...streams) .pipe($.browserSync.reload({ stream: true })); } From 04fea48cd570bdbd71d2b960db8cf8e8c1a99419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Mon, 29 Sep 2025 16:02:25 +0000 Subject: [PATCH 7/8] Disable resolve-url-loader debug mode; delete unnecessary importers option for NodePackageImporter (enabled by default) --- tasks/stylepack.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tasks/stylepack.js b/tasks/stylepack.js index 533151a..12c8386 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -54,9 +54,6 @@ function stylepack(gulp, $, config) { }, { loader: 'resolve-url-loader', - options: { - debug: true, - } }, { loader: "postcss-loader", @@ -86,7 +83,6 @@ function stylepack(gulp, $, config) { api: 'modern', sourceMap: true, sassOptions: { - // importers: new NodePackageImporter(), loadPaths: config.styles.includePaths ? config.styles.includePaths : [config.npmdir] }, }, From 4813d4f423595f5d982548940d4c8054f5a8574c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Birkemeyer?= Date: Mon, 29 Sep 2025 16:03:12 +0000 Subject: [PATCH 8/8] Tighten up PurgeCSS setup; add option to pass in postCssPresetEnvConfig per entrypoint --- tasks/stylepack.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tasks/stylepack.js b/tasks/stylepack.js index 12c8386..86789a8 100644 --- a/tasks/stylepack.js +++ b/tasks/stylepack.js @@ -14,13 +14,14 @@ function utilityCssExtractor(content) { function stylepack(gulp, $, config) { const streams = config.styles.files.map((file) => { - let purgeCssConfig = config.styles.purgeCss; + // Set up PurgeCSS with external config + let purgeCssConfig = file.purgeCss ?? config.styles.purgeCss; + let purgeCssDisabled = argv.purgecss === false; // Check for CLI flags/args + let purgeCss = purgeCssConfig && !purgeCssDisabled; // Determine if PurgeCSS should run - // Check for CLI flags/args - let purgeCssDisabled = argv.purgecss === false; - - // Determine if PurgeCSS should run - let purgeCss = purgeCssConfig && !purgeCssDisabled; + // Grab a PostCSS Preset Env config to use; + // always prefers a stylesheet-specific one over a global config for all CSS files + let postCssPresetEnvConfig = file.postCssPresetEnv || config.styles.postCssPresetEnv || ''; const webpackConfig = { entry: `/${config.webdir}/${file.files}`, @@ -61,7 +62,7 @@ function stylepack(gulp, $, config) { sourceMap: true, postcssOptions: { plugins: [ - ["postcss-preset-env"], + ["postcss-preset-env", postCssPresetEnvConfig], purgeCss ? postcssPurgecss({ content: purgeCssConfig.content, extractors: [