diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 0000000..dcaea13
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,28 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(ls:*)",
+ "Bash(mkdir:*)",
+ "Bash(pnpm dev)",
+ "Bash(pnpm test:*)",
+ "Bash(npx vitest run:*)",
+ "Bash(rg:*)",
+ "Bash(pnpm js:lint:*)",
+ "Bash(find:*)",
+ "Bash(npm test)",
+ "Bash(pnpm format:*)",
+ "Bash(npm run build:*)",
+ "Bash(npx prettier:*)",
+ "Bash(npm run dev:*)",
+ "Bash(pkill:*)",
+ "Bash(true)",
+ "Bash(pnpm export:*)",
+ "Bash(pnpm build:*)",
+ "Bash(grep:*)",
+ "Bash(npm run export:*)",
+ "Bash(rm:*)",
+ "Bash(node:*)"
+ ],
+ "deny": []
+ }
+}
diff --git a/.editorconfig b/.editorconfig
index 340ce2a..aad9567 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -26,6 +26,7 @@ insert_final_newline = ignore
[*.md]
trim_trailing_whitespace = false
+max_line_length = 80
[Makefile]
indent_style = tab
diff --git a/.env.example b/.env.example
index 3773fe6..bf562a3 100644
--- a/.env.example
+++ b/.env.example
@@ -1,3 +1,2 @@
-FTP_HOST=
-FTP_USER=
-FTP_PASSWORD=
+SITE_BASE_URL=https://gulp-devstack.cebre.us
+
diff --git a/.env.local b/.env.local
new file mode 100644
index 0000000..44e9933
--- /dev/null
+++ b/.env.local
@@ -0,0 +1,7 @@
+NODE_ENV=development
+SERVER_PORT=3000
+BROWSERSYNC_PORT=3001
+NODE_OPTIONS="--no-deprecation"
+LOG_LEVEL=debug
+
+SITE_BASE_URL=http://localhost:3000
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 89c23f1..0000000
--- a/.eslintignore
+++ /dev/null
@@ -1,23 +0,0 @@
-############################
-# Folders
-############################
-
-.cache
-.idea
-.temp
-.tmp
-build
-dist
-nbproject
-node_modules
-ssl
-static
-temp
-
-############################
-# Files
-############################
-
-*.html
-*.min.*
-package-lock.json
diff --git a/.eslintrc.yml b/.eslintrc.yml
deleted file mode 100755
index bf08e67..0000000
--- a/.eslintrc.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-env:
- browser: true
- commonjs: false
- es2021: true
-extends:
- - airbnb-base
- - plugin:prettier/recommended
- - plugin:jsdoc/recommended
-plugins:
- - prettier
- - require-sort
- - jsdoc
- - disable
-overrides:
- - files:
- - '*.js'
- settings:
- disable/plugins:
- - jsdoc
-parser: '@babel/eslint-parser'
-parserOptions:
- requireConfigFile: false
- babelrc: false
- configFile: false
- ecmaVersion: latest
- sourceType: module
- presets: ['@babel/preset-env']
-processor: 'disable/disable'
-rules:
- 'require-sort/require-sort': [warn, { 'ignoreCase': true }]
- no-param-reassign: ['error', { 'props': false }]
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 29e2514..0e4b21c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,8 +5,8 @@
version: 2
updates:
- - package-ecosystem: "npm"
- directory: "/"
- target-branch: "develop"
+ - package-ecosystem: 'npm'
+ directory: '/'
+ target-branch: 'develop'
schedule:
- interval: "weekly"
+ interval: 'weekly'
diff --git a/.github/instructions/js.instructions.md b/.github/instructions/js.instructions.md
new file mode 100644
index 0000000..b099870
--- /dev/null
+++ b/.github/instructions/js.instructions.md
@@ -0,0 +1,24 @@
+---
+applyTo: '**/*.js'
+---
+
+JavaScript files must follow these standards (see also REFACTORING\_GUIDE.md):
+
+* Use modern ES Modules syntax (`import`/`export`), never CommonJS
+ (`require`/`module.exports`).
+* Always use `async/await` for asynchronous code; avoid callbacks and
+ unnecessary Promise wrapping.
+* Write clear, descriptive JSDoc comments for all exported functions.
+* Prefer small, pure functions and avoid deep nesting.
+* Follow DRY, KISS, and SOLID principles.
+* Use English for all code, variable names, comments, and documentation.
+* Variable and function names must be in camelCase.
+* Place reusable logic in utility modules.
+* Log errors and important events using the project logger.
+* Do not use the unary increment/decrement operators (`++`, `--`).
+* Always run and maintain tests for all modules using `node:test` and
+ `node:assert`.
+* Run ESLint and Prettier to ensure code quality and formatting.
+* If anything is unclear, ask for clarification.
+
+All code must be readable, maintainable, and secure.
diff --git a/.github/instructions/md.instructions.md b/.github/instructions/md.instructions.md
new file mode 100644
index 0000000..57402d3
--- /dev/null
+++ b/.github/instructions/md.instructions.md
@@ -0,0 +1,17 @@
+---
+applyTo: '**/*.md'
+---
+
+Markdown files must follow these standards (see also REFACTORING\_GUIDE.md):
+
+* Write all documentation, guides, and comments in clear, concise English.
+* Use structured headings, bullet points, and code blocks for clarity.
+* Document the purpose, usage, and data schema of each component or module.
+* Include practical examples and sample code where helpful.
+* Keep documentation up to date with code and architectural changes.
+* Prefer short paragraphs and simple language for readability.
+* Use consistent formatting and follow any project-specific style guides.
+* Link to related files or sections where relevant.
+* If anything is unclear, ask for clarification.
+
+All documentation must be easy to read, maintain, and extend.
diff --git a/.github/instructions/njk.instructions.md b/.github/instructions/njk.instructions.md
new file mode 100644
index 0000000..3c12d9b
--- /dev/null
+++ b/.github/instructions/njk.instructions.md
@@ -0,0 +1,26 @@
+---
+applyTo: '**/*.njk'
+---
+
+Nunjucks templates must follow these standards (see also REFACTORING\_GUIDE.md):
+
+* Always use Bootstrap utility classes for layout and spacing first; only create
+ custom `u-` utilities if Bootstrap does not provide the required
+ functionality.
+* Use BEM naming conventions for all CSS classes (e.g., `c-card__title`,
+ `u-text-glow`).
+* Each reusable component must have its own folder and `.njk`, `.scss`, and
+ `.md` files.
+* Pass data to components using `{% set %}`; avoid the `with` syntax unless
+ absolutely necessary.
+* Always validate the existence of data before rendering (e.g.,
+ `{% if variable %}`).
+* Prefer simple, flat data structures for component inputs.
+* Extract repeated blocks into partials for reuse.
+* Write clear, descriptive comments in English.
+* Ensure all template logic is readable and maintainable.
+* Avoid deep nesting and complex inline logic.
+* All code, comments, and documentation must be in English.
+* Document each component’s data schema in its `.md` file.
+
+If you encounter unclear requirements, ask for clarification.
diff --git a/.github/instructions/scss.instructions.md b/.github/instructions/scss.instructions.md
new file mode 100644
index 0000000..7d8c2b5
--- /dev/null
+++ b/.github/instructions/scss.instructions.md
@@ -0,0 +1,21 @@
+---
+applyTo: '**/*.scss'
+---
+
+SCSS files must follow these standards (see also REFACTORING\_GUIDE.md):
+
+* Use BEM naming conventions for all classes: `c-` for components, `o-` for
+ objects, `u-` for utilities.
+* Always prefer Bootstrap utility classes for layout and spacing; create custom
+ `u-` utilities only if Bootstrap does not provide the required functionality.
+* Each component must have its own SCSS file, starting with its BEM class.
+* Avoid deep nesting; keep selectors as flat as possible.
+* Use mixins and variables for repeated logic and values.
+* Write clear, descriptive comments in English.
+* Do not duplicate Bootstrap utilities.
+* Keep custom utilities (`u-`) single-purpose and project-specific.
+* Run Stylelint and Prettier to ensure code quality and formatting.
+* If anything is unclear, ask for clarification.
+
+All styles must be readable, maintainable, and consistent with the project’s
+architecture.
diff --git a/.github/instructions/test.instructions.md b/.github/instructions/test.instructions.md
new file mode 100644
index 0000000..3a9e987
--- /dev/null
+++ b/.github/instructions/test.instructions.md
@@ -0,0 +1,18 @@
+---
+applyTo: '**/*.test.js'
+---
+
+Test files must follow these standards (see also REFACTORING\_GUIDE.md):
+
+* Use the `node:test` runner and `node:assert` for all tests.
+* Each test case must have a clear, descriptive name in English.
+* Cover all important use cases, including edge cases and error handling.
+* Keep tests isolated and independent; avoid shared state between tests.
+* Use mock data and file system mocking where appropriate.
+* Prefer small, focused test functions over large, complex ones.
+* Write clear comments explaining the purpose of each test section.
+* Ensure all tests are readable, maintainable, and easy to extend.
+* Run tests frequently and keep them up to date with code changes.
+* If anything is unclear, ask for clarification.
+
+All test code, comments, and documentation must be in English.
diff --git a/.github/prompts/refactor.prompt.md b/.github/prompts/refactor.prompt.md
new file mode 100644
index 0000000..42dcb1d
--- /dev/null
+++ b/.github/prompts/refactor.prompt.md
@@ -0,0 +1,54 @@
+***
+
+## mode: agent
+
+Refactor given code project according to all the rules, policies leadin g to a
+more maintainable, secure, and efficient codebase.
+
+Your goal is to help select the most effective tools and strategies, reducing
+duplication and complexity. Always proceed as follows:
+
+1\. Conduct a thorough review of the existing code and, inside
+``, provide a detailed analysis of how the code
+works, highlighting key components and their interactions. Identify any
+potential issues, areas for improvement, or security vulnerabilities.
+
+2\. After reviewing, outline your recommendations inside ``.
+This should include a detailed plan for refactoring, including any necessary
+changes to the code structure, variable names, and comments. If you identify
+any issues or areas for improvement, document them clearly, specifying the
+rationale behind each recommendation.
+
+3\. Always be mindful of potential security risks like unsafe input handling or
+authentication vulnerabilities. Conduct a thorough analysis and include your
+findings inside ``.
+
+\- As you progress, consider hosting, management, monitoring, and maintenance
+implications, ensuring solutions remain robust and practical.
+\- Seek clarification on any unclear points and discuss trade-offs when multiple
+options arise.
+\- When refactoring code, apply established principles such as SOLID, DRY, YAGNI,
+and KISS.
+\- Standardize variable names and maintain readability, preserving existing
+console logs and comments but extending them as needed.
+\- If no obvious problems appear in the code, indicate that it seems fine and
+request a stack trace or additional information.
+\- Optimize for speed and efficiency. Use async/await appropriately without
+placing await in loops or nesting loops within async code.
+\- Avoid using the unary operator ++, and prefer a functional approach over
+classes where possible.
+\- In all cases, keep the focus on reducing duplication, maintaining clarity, and
+ensuring the code is both secure and performant.
+\- Insert before and after these tags ``,
+``, and `` blank lines
+to ensure proper readability and formatting.
+
+You can automatically run CLI commands that are enabled in
+`.claude/settings.local.json` (e.g. lint, test, build, etc.).
+
+Communication and input will be in Czech, and all code, variable names,
+comments, and documentation must be in English.
+
+If you run into ambiguity, prefer readability, simplicity, and explicitness. The
+result must be consistent with the examples and anti-patterns provided in the
+guide.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 2ad3326..c24cf49 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -16,13 +16,13 @@ Replace [ ] by [x] to check these checkboxes!
#### My PR is a:
-- [ ] 💥 Breaking change
-- [ ] 🐛 Bug fix
-- [ ] 💅 Enhancement
-- [ ] 🚀 New feature
+* [ ] 💥 Breaking change
+* [ ] 🐛 Bug fix
+* [ ] 💅 Enhancement
+* [ ] 🚀 New feature
#### Main update on the:
-- [ ] Templates and Code
-- [ ] Framework
-- [ ] Documentation
+* [ ] Templates and Code
+* [ ] Framework
+* [ ] Documentation
diff --git a/.github/workflows/github-pages-deploy-pnpm.yml b/.github/workflows/github-pages-deploy-pnpm.yml
index 3124ffb..85d0dec 100644
--- a/.github/workflows/github-pages-deploy-pnpm.yml
+++ b/.github/workflows/github-pages-deploy-pnpm.yml
@@ -2,9 +2,9 @@ name: Build and Deploy
on:
push:
- branches: ["master"]
+ branches: ['master']
workflow_dispatch:
- branches: ["master", "develop"]
+ branches: ['master', 'develop']
permissions:
contents: read
@@ -12,11 +12,14 @@ permissions:
id-token: write
concurrency:
- group: "pages"
+ group: 'pages'
cancel-in-progress: false
jobs:
build-and-deploy:
+ strategy:
+ matrix:
+ node-version: [22.x]
runs-on: ubuntu-latest
environment:
name: github-pages
@@ -24,25 +27,27 @@ jobs:
steps:
- name: Checkout 🔄
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup PNPM 📦
- uses: pnpm/action-setup@v2
+ uses: pnpm/action-setup@v4
with:
- version: 8
+ version: 10
- name: Setup Node.js ${{ matrix.node-version }} 🟢
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Cache dependencies 🗄️
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
- name: Install dependencies ⬇️
- run: pnpm install
+ run: pnpm install --prod # --ignore-scripts
+ env:
+ CI: true
- name: Build project 🔨
run: pnpm build
- name: Inspect build output 🔍
@@ -50,11 +55,11 @@ jobs:
ls -lah ./build
du -sh ./build
- name: Setup Pages ⚙️
- uses: actions/configure-pages@v3
+ uses: actions/configure-pages@v5
- name: Upload artifact 📤
- uses: actions/upload-pages-artifact@v1
+ uses: actions/upload-pages-artifact@v3
with:
path: 'build'
- name: Deploy to GitHub Pages 🚀
id: deployment
- uses: actions/deploy-pages@v2
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index 32ad577..74ff403 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,6 +86,9 @@ Thumbs.db
*.bak
*#
build
+build-dev
+build-export
+build-prod
dist
export
nbproject
diff --git a/.npmrc b/.npmrc
index 081e89e..2068f54 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,4 +1,2 @@
-engine-strict = true
-link-workspace-packages = true
-shamefully-hoist = true
+engine-strict=true
strict-peer-dependencies=false
diff --git a/.nvmrc b/.nvmrc
index 3f430af..53d1c14 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v18
+v22
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..d3d8a81
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,57 @@
+const config = {
+ arrowParens: 'always',
+ bracketSameLine: false,
+ bracketSpacing: true,
+ endOfLine: 'lf',
+ semi: false,
+ singleQuote: true,
+ tabWidth: 2,
+ trailingComma: 'es5',
+ useTabs: false,
+ importOrder: [
+ '',
+ '^gulp$',
+ '^./gulpconfig',
+ '',
+ '^[./]',
+ ],
+ importOrderSeparation: true,
+ importOrderSortSpecifiers: true,
+ plugins: [
+ '@trivago/prettier-plugin-sort-imports',
+ 'prettier-plugin-jinja-template',
+ ],
+ overrides: [
+ {
+ files: '*.njk',
+ options: {
+ parser: 'jinja-template',
+ printWidth: 120,
+ htmlWhitespaceSensitivity: 'strict',
+ },
+ },
+ {
+ files: '*.js',
+ options: {
+ printWidth: 80,
+ singleQuote: true,
+ arrowParens: 'always',
+ },
+ },
+ {
+ files: '*.json',
+ options: {
+ useTabs: true,
+ },
+ },
+ {
+ files: '*.md',
+ options: {
+ printWidth: 80,
+ proseWrap: 'always',
+ },
+ },
+ ],
+}
+
+export default config
diff --git a/.prettierrc.yml b/.prettierrc.yml
deleted file mode 100644
index fc743a9..0000000
--- a/.prettierrc.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-endOfLine: lf
-tabWidth: 2
-useTabs: false
-singleQuote: true
-bracketSpacing: true
-semi: true
-arrowParens: always
-
-overrides:
- - files:
- - '*.js'
- options:
- printWidth: 80
- - files:
- - '*.json'
- options:
- useTabs: true
- # - files:
- # - 'Makefile'
- # options:
- # useTabs: true
- - files:
- - '*.yml'
- - '*.yaml'
- - 'package.json'
- options:
- tabWidth: 2
- useTabs: false
- # - files:
- # - '*.html'
- # options:
- # htmlWhitespaceSensitivity: ignore
diff --git a/.release-it.yml b/.release-it.yml
index 90eaa5b..ab6aecc 100644
--- a/.release-it.yml
+++ b/.release-it.yml
@@ -50,7 +50,7 @@ plugins:
- file: content/pages/index.md
search: v\d+\.\d+\.\d+
replace: v{{versionWithoutPrerelease}}
- - file: src/templates/layout-default.html
+ - file: src/routes/layout-default.njk
search: data-version="\d+\.\d+\.\d+
replace: data-version="{{versionWithoutPrerelease}}
- file: gulpconfig.build.js
diff --git a/.remarkrc.js b/.remarkrc.js
new file mode 100644
index 0000000..8c29666
--- /dev/null
+++ b/.remarkrc.js
@@ -0,0 +1,30 @@
+// .remarkrc.js
+import remarkFrontmatter from 'remark-frontmatter'
+import remarkGfm from 'remark-gfm'
+import remarkLintCode from 'remark-lint-code'
+import remarkLintHeadingWhitespace from 'remark-lint-heading-whitespace'
+import remarkLintMatchPunctuation from 'remark-lint-match-punctuation'
+import remarkLintNoDuplicateHeadings from 'remark-lint-no-duplicate-headings'
+import remarkPresetLintConsistent from 'remark-preset-lint-consistent'
+import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
+
+/** @type {import('unified').Preset} */
+const config = {
+ plugins: [
+ remarkFrontmatter,
+ remarkGfm,
+ remarkPresetLintRecommended,
+ remarkPresetLintConsistent,
+ remarkLintCode,
+ remarkLintHeadingWhitespace,
+ remarkLintMatchPunctuation,
+ ],
+ overrides: [
+ {
+ files: 'src/routes/**/*.md',
+ plugins: [remarkLintNoDuplicateHeadings],
+ },
+ ],
+}
+
+export default config
diff --git a/.remarkrc.yml b/.remarkrc.yml
deleted file mode 100644
index a0eba81..0000000
--- a/.remarkrc.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-plugins:
- - remark-preset-lint-markdown-style-guide
- - remark-gfm
- - remark-frontmatter
- - remark-lint-match-punctuation
- - remark-preset-lint-consistent
- - remark-preset-lint-recommended
- - remark-lint-heading-whitespace
- - remark-lint-no-dead-urls
- - remark-lint-code
diff --git a/.stylelintrc.js b/.stylelintrc.js
new file mode 100644
index 0000000..a0768ff
--- /dev/null
+++ b/.stylelintrc.js
@@ -0,0 +1,44 @@
+export default {
+ plugins: [
+ 'stylelint-high-performance-animation',
+ 'stylelint-selector-bem-pattern',
+ ],
+ extends: [
+ 'stylelint-config-standard-scss',
+ '@visionappscz/stylelint-config',
+ '@visionappscz/stylelint-config/order',
+ '@visionappscz/stylelint-config/scss',
+ 'stylelint-config-prettier-scss',
+ ],
+ customSyntax: 'postcss-scss',
+ rules: {
+ 'unit-allowed-list': [
+ 'px',
+ 'rem',
+ 'em',
+ '%',
+ 's',
+ 'deg',
+ 'vh',
+ 'vw',
+ 'dvw',
+ 'ch',
+ ],
+ 'plugin/no-low-performance-animation-properties': true,
+ 'plugin/selector-bem-pattern': {
+ preset: 'bem',
+ implicitComponents: '**/c-*.scss',
+ componentName: '(([a-z0-9]+(?!-$)-?)+)',
+ componentSelectors: {
+ initial:
+ "\\.{componentName}(((__|--)(([a-z0-9\\[\\]'=]+(?!-$)-?)+))+)?$",
+ },
+ implicitUtilities: '**/u-*.scss',
+ utilitySelectors: '^\\.u-[a-z]+$',
+ },
+ // Reset for visionapps
+ 'selector-nested-pattern': null,
+ 'selector-class-pattern': null,
+ },
+ ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
+}
diff --git a/.stylelintrc.yml b/.stylelintrc.yml
deleted file mode 100644
index b2dd4bb..0000000
--- a/.stylelintrc.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-plugins:
- - stylelint-high-performance-animation
- - stylelint-selector-bem-pattern
-
-extends:
- - '@visionappscz/stylelint-config'
- - '@visionappscz/stylelint-config/order'
- - '@visionappscz/stylelint-config/scss'
- - stylelint-config-recommended-scss
-
-rules:
- indentation: 2
- linebreaks: 'unix'
- unit-allowed-list: ['px', 'rem', '%', 's', 'deg']
-
- plugin/no-low-performance-animation-properties: true
-
- plugin/selector-bem-pattern:
- preset: 'bem'
- implicitComponents: '**/c-*.scss'
- componentName: '(([a-z0-9]+(?!-$)-?)+)'
- componentSelectors:
- initial: "\\.{componentName}(((__|--)(([a-z0-9\\[\\]'=]+(?!-$)-?)+))+)?$"
- implicitUtilities: '**/u-*.scss'
- utilitySelectors: "^\\.u-[a-z]+$"
-
- # Reset for visionapps
- string-quotes: single
- selector-nested-pattern: null
- selector-class-pattern:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2937097..f2047a8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,40 @@
# Front-end Gulp DevStack Changelog
+## [4.5.0](https://github.com/cebreus/gulp-devstack/compare/4.4.0...4.5.0) (2024-05-13)
+
+> It contains Bootstrap 5.3.2, Node,je version bump to 18.x, security updates
+> and major package upgrades.
+
+### ⚠️ BREAKING CHANGES
+
+* Node.js version bump to 18.x
+* Update GitHub Actions to latest versions
+
+### 🚀 New Features
+
+* Update Bootstrap to 5.3.2
+
+### Other changes
+
+* fix: `gulp-todo.js`
+* fix: callbacks
+* refactor: logging
+* refactor: documentation
+* refactor: linters
+
+## [4.4.1](https://github.com/cebreus/gulp-devstack/compare/4.0.0...4.4.1) (2023-07-03)
+
+> Fix a glob in the `copyStaticFnc()` function, refactor the `buildTodo()`
+> function and security updates.
+
## [4.4.0](https://github.com/cebreus/gulp-devstack/compare/4.0.0...4.4.0) (2023-06-12)
> It contains Bootstrap 5.3.0, security updates and major package upgrades.
### 🚀 New Features
-* feat: upgrade Bootstrap to 5.3.0
-* feat: new GitHub action for deployment to GitHub Pages
+* feat: upgrade Bootstrap to 5.3.0
+* feat: new GitHub action for deployment to GitHub Pages
## Release [4.3.1](https://github.com/cebreus/gulp-devstack/compare/4.0.0...4.3.1) (2023-05-30)
@@ -19,7 +46,8 @@
## Release [4.2.0](https://github.com/cebreus/gulp-devstack/compare/4.0.0...4.2.0) (2023-03-29)
-> Security updates, minor enhancements and upgrade of gulp-imagemin to version 8.
+> Security updates, minor enhancements and upgrade of gulp-imagemin to
+> version 8.
## Release [4.1.1](https://github.com/cebreus/gulp-devstack/compare/4.0.0...4.1.1) (2023-03-29)
@@ -27,52 +55,54 @@
## Release [4.1.0](https://github.com/cebreus/gulp-devstack/compare/4.0.0...4.1.0) (2023-01-29)
-> Code cleanup, security fixes, major code maintenance, Stylelint fixes and Babel upgrade.
+> Code cleanup, security fixes, major code maintenance, Stylelint fixes and
+> Babel upgrade.
### 🚀 New Features
-* feat: update Bootstrap to 5.2.3
+* feat: update Bootstrap to 5.2.3
## Release [4.0.0](https://github.com/cebreus/gulp-devstack/compare/3.5.0...4.0.0) (2022-10-05)
-> **Major release!** Refactored all Gulp tasks and scripts. Contains Bootstrap 5.2.2 and security updates.
+> **Major release!** Refactored all Gulp tasks and scripts. Contains Bootstrap
+> 5.2.2 and security updates.
### ⚠️ BREAKING CHANGES
-* refactor: all Gulp tasks and scripts
+* refactor: all Gulp tasks and scripts
### 🚀 New Features
-* feat: update Bootstrap to 5.2.2
-* feat: new header on 404 page
+* feat: update Bootstrap to 5.2.2
+* feat: new header on 404 page
### Other changes
-* refactor: textlint rules
-* refactor: eslint rules
-* refactor: npm script 'todo'
-* refactor: release process
-* fix: use local instance of the Gulp
-* fix: npm script 'prepare'
-* chore: npm up
+* refactor: textlint rules
+* refactor: eslint rules
+* refactor: npm script 'todo'
+* refactor: release process
+* fix: use local instance of the Gulp
+* fix: npm script 'prepare'
+* chore: npm up
## Release [3.5.0](https://github.com/cebreus/gulp-devstack/compare/3.4.0...3.5.0) (2022-06-20)
> Security updates, Bootstrap 5.2.0 and minor fixes and refactors.
-* feat: update Bootstrap to 5.2.0
-* refactor: calling if the npm scripts
-* fix: unresolved variable
-* fix: fs-read() encoding to 'utf8'
+* feat: update Bootstrap to 5.2.0
+* refactor: calling if the npm scripts
+* fix: unresolved variable
+* fix: fs-read() encoding to 'utf8'
## Release [3.4.0](https://github.com/cebreus/gulp-devstack/compare/3.3.1...3.4.0) (2022-02-02)
> Update to Node.js 16 and cross-platform fixes.
-* Node.js 16
-* Prefix relative paths in export with '.'
-* Add caching to GitHub workflow
-* Add VS code extensions recommendations
+* Node.js 16
+* Prefix relative paths in export with '.'
+* Add caching to GitHub workflow
+* Add VS code extensions recommendations
## Release [3.3.1](https://github.com/cebreus/gulp-devstack/compare/3.3.0...3.3.1) (2021-12-01)
@@ -82,9 +112,9 @@
### 🚀 New Features
-* Brand new landing page.
-* Refactor Twitter cards markup.
-* GitHub workflow for install, build and deploy to GitHub Pages.
+* Brand new landing page.
+* Refactor Twitter cards markup.
+* GitHub workflow for install, build and deploy to GitHub Pages.
## Release [3.2.0](https://github.com/cebreus/gulp-devstack/compare/3.1.1...3.2.0) (2021-11-11)
@@ -92,21 +122,23 @@ Updated npm packages include `gulp-sass` (version 5) & `sass` (Dart Sass).
### 🚀 New Features
-* feat: Bootstrap 5.1.3 [`60da2f6`](https://github.com/cebreus/gulp-devstack/commit/60da2f6b6d7343c41c09983cdfd8ba604a6195c1)
+* feat: Bootstrap 5.1.3
+ [`60da2f6`](https://github.com/cebreus/gulp-devstack/commit/60da2f6b6d7343c41c09983cdfd8ba604a6195c1)
## Release [3.1.1](https://github.com/cebreus/gulp-devstack/compare/3.1.0...3.1.1) (2021-09-22)
Required node 14.x, updated npm packages
-* fix: husky execute
-* fix: validation of HTML
-* refactor: remove gitmodule git-release
+* fix: husky execute
+* fix: validation of HTML
+* refactor: remove gitmodule git-release
## Release [3.1.0](https://github.com/cebreus/gulp-devstack/compare/3.0.0...3.1.0) (2021-05-30)
### 🚀 New Features
-* feat: Bootstrap 5.0.1 [`507d13c`](https://github.com/cebreus/gulp-devstack/commit/507d13c45b77e1fc47ee8c232ddba165649946a6)
+* feat: Bootstrap 5.0.1
+ [`507d13c`](https://github.com/cebreus/gulp-devstack/commit/507d13c45b77e1fc47ee8c232ddba165649946a6)
## Release [3.0.0](https://github.com/cebreus/gulp-devstack/compare/2.0.0...3.0.0) (2021-03-10)
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..9943b9e
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,97 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Build Commands
+
+### Development & Production
+* `npm run dev` / `pnpm dev` - Start development with hot-reload (main development command)
+* `npm run build` - Production build (optimized, minified, hashed assets)
+* `npm run export` - Export build (readable, formatted code for collaboration)
+* `npm run debug` - Run with debug logging enabled
+* `npm run todo` / `npm run todo:show` - Generate and display TODO reports
+
+### Testing
+* `npm test` - Run Node.js test suite using built-in test runner (tests in `gulp/tasks/*.test.js`)
+
+### Lint/Format Commands
+* `pnpm format` - Format all files (JS, SCSS, Markdown) with Prettier and linters
+* `pnpm js:lint` / `pnpm js:fix` - ESLint JavaScript files
+* `pnpm css:lint` / `pnpm css:fix` - Stylelint SCSS files
+* `pnpm text:lint` / `pnpm text:fix` - Remark lint Markdown files
+
+### Component Management
+* `pnpm component:create` - Interactive component creation
+* `pnpm component:remove` - Remove existing component
+* `pnpm component:list` - List all components
+* `COMPONENT_NAME=my-component pnpm component:create` - Create component with environment variable
+
+## Architecture Overview
+
+### Build System
+This project uses **Gulp 5** with three distinct build modes:
+- **Development** (`gulpfile.js`) - Fast builds with source maps, hot-reload via BrowserSync
+- **Export** (`gulpfile.export.js`) - Formatted output for developer collaboration
+- **Production** (`gulpfile.build.js`) - Optimized with minification, PurgeCSS, asset hashing, SRI
+
+### Component System
+Components are modular UI elements in `/src/lib/components/[name]/`:
+- `[name].njk` - Nunjucks template with BEM classes (`.c-[name]`)
+- `[name].scss` - Component styles following BEM methodology
+- `[name].md` - Documentation (auto-generated)
+
+Components are automatically compiled and injected into the build.
+
+### Routing & Content
+**File-based routing** (SvelteKit-style) in `/src/routes/`:
+- `.md` files become pages (converted to JSON for templates)
+- `.njk` files are Nunjucks templates
+- `layout-default.njk` is the main layout (not rendered as page)
+- Frontmatter in Markdown files provides page metadata
+
+### Template System
+- **Nunjucks** templating with custom filters and global data
+- Global site configuration in `/src/config/site.js`
+- Templates have access to processed Markdown content as JSON
+- Components can be included with `{% include "components/[name]/[name].njk" %}`
+
+### Asset Processing
+- **SCSS**: Bootstrap 5.3 + custom styles, BEM methodology, PostCSS with Autoprefixer
+- **JavaScript**: ES modules, Babel transpilation, concatenation
+- **Images**: Optimization with imagemin (JPG/SVG) and UPNG (PNG)
+- **Fonts**: Google Fonts via `fonts.list` configuration
+
+## Code Style Guidelines
+
+### JavaScript
+- ES modules with `.js` extension
+- JSDoc required on all functions (`eslint-plugin-jsdoc`)
+- Prettier formatting: singleQuote, 2-space indentation, 80 char line length
+
+### SCSS/CSS
+- **BEM methodology**: `.block__element--modifier`
+- Component styles prefixed with `.c-` (e.g., `.c-header`)
+- Object styles prefixed with `.o-` (e.g., `.o-container`)
+- Utility styles prefixed with `.u-` (e.g., `.u-text-center`)
+
+### Templates & Naming
+- **Nunjucks** (.njk) for HTML templating
+- **kebab-case** for files and CSS classes
+- **camelCase** for JavaScript variables
+- **Conventional commits** (feat, fix, docs, refactor, etc.)
+
+### Formatting
+- 2-space indentation throughout
+- LF line endings
+- Prettier handles most formatting automatically
+
+## Key Configuration Files
+
+- `gulp/gulpconfig.js` - Main Gulp configuration (paths, settings)
+- `src/config/site.js` - Site metadata and global content
+- `eslint.config.js` - ESLint configuration with JSDoc enforcement
+- `package.json` - Scripts and dependencies (Node.js 22+ required)
+
+## Testing
+
+Tests use Node.js built-in test runner with files in `gulp/tasks/*.test.js`. Component tests validate creation, removal, and renaming functionality with prompts and file system operations.
diff --git a/README.md b/README.md
index 891e310..14014c3 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,8 @@
# Front-end Gulp DevStack
-> Gulp stack for building optimized static pages and exports for collaboration between coders and programmers.
+> Gulp stack for building optimized static pages and exports for collaboration
+> between coders and programmers.
@@ -17,22 +18,23 @@
-* [Typical use cases](#typical-use-cases)
-* [Features](#features)
- * [Something more under the hood](#something-more-under-the-hood)
-* [Getting Started](#getting-started)
- * [Installation](#installation)
-* [Project structure](#project-structure)
-* [Workflow](#workflow)
- * [Development](#development)
- * [Production Build](#production-build)
- * [Export Build](#export-build)
-* [Updates from devstack to your existing project](#updates-from-devstack-to-your-existing-project)
-* [Inject devstack to your new project](#inject-devstack-to-your-new-project)
-* [Roadmap and Known issues](#roadmap-and-known-issues)
-* [Contributing](#contributing)
-* [License](#license)
-* [Contact](#contact)
+* [Front-end Gulp DevStack](#front-end-gulp-devstack)
+ * [Typical use cases](#typical-use-cases)
+ * [Features](#features)
+ * [Something more under the hood](#something-more-under-the-hood)
+ * [Getting Started](#getting-started)
+ * [Installation](#installation)
+ * [Project structure](#project-structure)
+ * [Workflow](#workflow)
+ * [Development](#development)
+ * [Production Build](#production-build)
+ * [Export Build](#export-build)
+ * [Updates from devstack to your existing project](#updates-from-devstack-to-your-existing-project)
+ * [Inject devstack to your new project](#inject-devstack-to-your-new-project)
+ * [Roadmap and Known issues](#roadmap-and-known-issues)
+ * [Contributing](#contributing)
+ * [License](#license)
+ * [Contact](#contact)
@@ -41,20 +43,36 @@
## Typical use cases
-* Developing landing pages or prototypes (`npm run dev`).
-* Building carefully compiled and formated files for collaboration (`npm run export`).
-* Building the final (production) bundle, ready for deployment (`npm run deploy`).
+* Developing landing pages or prototypes (`npm run dev`).
+* Building carefully compiled and formated files for collaboration
+ (`npm run export`).
+* Building the final (production) bundle, ready for deployment
+ (`npm run deploy`).
-When you want to build whole web sites from the data sources as API or many markdown files, go with Static Page Generators (SGC). For example [Gridsome](https://gridsome.org/) (VueJS), [Gatsby](https://www.gatsbyjs.org/) (React) or [Hugo](https://gohugo.io/) (Go) will work for you much better.
+When you want to build whole web sites from the data sources as API or many
+markdown files, go with Static Page Generators (SGC). For example
+[Gridsome](https://gridsome.org/) (VueJS), [Gatsby](https://www.gatsbyjs.org/)
+(React) or [Hugo](https://gohugo.io/) (Go) will work for you much better.
## Features
-* SEO-friendly — Open Graph and Twiter Cards markup, self/canonical.
-* User-friendly — image optimizations, favicons, webmanifest and all sources minification to smallest bundle.
-* Developer-friendly — [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [Remark](https://remark.js.org/), [Stylelint](https://stylelint.io/) via tasks or with [Husky](https://github.com/typicode/husky) and [Lint staged](https://github.com/okonet/lint-staged).
-* Separate tasks for Development, Export and Build with automatic renaming and hashing all critical assets.
-* Ready for implementation Git based CMS as [Tina CMS](https://tina.io/) or [Netlify CMS](https://www.netlifycms.org/) etc. — Front Matter (Markdown files metadata and content).
-* HTML temlates uses [Nunjucks](https://mozilla.github.io/nunjucks/). Fully customisable [Bootstrap 5.3.x](https://getbootstrap.com/) extended with [BEM](https://en.bem.info/). JavaScript processed with [Babel](https://babeljs.io/) or injected from CDN or as static files.
+* SEO-friendly — Open Graph and Twiter Cards markup, self/canonical.
+* User-friendly — image optimizations, favicons, webmanifest and all sources
+ minification to smallest bundle.
+* Developer-friendly — [ESLint](https://eslint.org/),
+ [Prettier](https://prettier.io/), [Remark](https://remark.js.org/),
+ [Stylelint](https://stylelint.io/) via tasks or with
+ [Husky](https://github.com/typicode/husky) and
+ [Lint staged](https://github.com/okonet/lint-staged).
+* Separate tasks for Development, Export and Build with automatic renaming and
+ hashing all critical assets.
+* Ready for implementation Git based CMS as [Tina CMS](https://tina.io/) or
+ [Netlify CMS](https://www.netlifycms.org/) etc. — Front Matter (Markdown files
+ metadata and content).
+* HTML temlates uses [Nunjucks](https://mozilla.github.io/nunjucks/). Fully
+ customisable [Bootstrap 5.3](https://getbootstrap.com/) extended with
+ [BEM](https://en.bem.info/). JavaScript processed with
+ [Babel](https://babeljs.io/) or injected from CDN or as static files.
***
@@ -72,125 +90,220 @@ When you want to build whole web sites from the data sources as API or many mark
### Something more under the hood
-* Linting all commit messages by [CommitLint](https://commitlint.js.org/), see more about [Semantic Commit Messages](https://seesparkbox.com/foundry/semantic_commit_messages) and [Conventional Commits](https://www.conventionalcommits.org/)
-* Commit guide on the CLI by [git-cz](https://github.com/streamich/git-cz)
-* Automatic releases with [Release It!](https://github.com/release-it/release-it), see more about [Semantic Versioning](https://semver.org/)
-* Changelog with [Conventional Changelog](https://github.com/conventional-changelog/conventional-changelog)
-* [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)
-* Build and deployment to FTP.
+* Linting all commit messages by [CommitLint](https://commitlint.js.org/), see
+ more about
+ [Semantic Commit Messages](https://seesparkbox.com/foundry/semantic_commit_messages)
+ and [Conventional Commits](https://www.conventionalcommits.org/)
+* Commit guide on the CLI by [git-cz](https://github.com/streamich/git-cz)
+* Automatic releases with
+ [Release It!](https://github.com/release-it/release-it), see more about
+ [Semantic Versioning](https://semver.org/)
+* Changelog with
+ [Conventional Changelog](https://github.com/conventional-changelog/conventional-changelog)
+* [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)
## Getting Started
### Installation
-1. [Node.js and npm](https://nodejs.org/en/) are required.
+1. [Node.js and npm](https://nodejs.org/en/) are required.
-2. Clone the repository into the new project directory `PROJECT_NAME`
+ Node.js version **22.x** (LTS) is required. Please use
+ [nvm](https://github.com/nvm-sh/nvm) or [Volta](https://volta.sh/) to manage
+ your Node.js versions.
- ```bash
- git clone https://github.com/cebreus/gulp-devstack/ ./PROJECT_NAME
- ```
+2. Clone the repository into the new project directory `PROJECT_NAME`
-3. Go to project directory `PROJECT_NAME` and install npm dependencies
+ ```bash
+ git clone https://github.com/cebreus/gulp-devstack/ ./PROJECT_NAME
+ ```
- ```bash
- cd PROJECT_NAME && npm i
- ```
+3. Go to project directory `PROJECT_NAME` and install npm dependencies
-4.
- Optional clenup (click to expand)
+ ```bash
+ cd PROJECT_NAME && npm i
+ ```
- * Clean `CHANGELOG.md`
+4.
+ Optional clenup (click to expand)
+ - Clean `CHANGELOG.md`
- ```bash
- > CHANGELOG.md
- ```
+ ```bash
+ > CHANGELOG.md
+ ```
- * Change or remove `LICENSE.txt` by `rm LICENSE`
+ * Change or remove `LICENSE.txt` by `rm LICENSE`
- ```bash
- rm LICENSE
- ```
+ ```bash
+ rm LICENSE
+ ```
- * Change this `README.md` according to your new project or replace it from the template
+ * Change this `README.md` according to your new project or replace it from
+ the template
- ```bash
- curl https://gist.githubusercontent.com/cebreus/a6010a2a95a4f2375830b0af3193f2f9/raw/cde6d9c68f2605b34eb5b8710bd553e7ad28a678/minimalistic-readme > README.md
- ```
+ ```bash
+ curl https://gist.githubusercontent.com/cebreus/a6010a2a95a4f2375830b0af3193f2f9/raw/cde6d9c68f2605b34eb5b8710bd553e7ad28a678/minimalistic-readme > README.md
+ ```
- * Change these data in the `package.json` accordng to your new project
- * `name`
- * `description`
- * `keywords`
- * `author`
- * `license`
- * `private`
- * `repository`
- * `homepage`
- * `bugs`
+ * Change these data in the `package.json` accordng to your new project
+
+ * `name`
+ * `description`
+ * `keywords`
+ * `author`
+ * `license`
+ * `private`
+ * `repository`
+ * `homepage`
+ * `bugs`
## Project structure
-* ### `/.github`
- Specialties designed for GitHub.
-* ### `/content`
- * `/pages` — each `*.md` is data source for templates; each file corresponds to the template `./src/pages/*.html`
- * `site.md` — contains default data for all pages
-* ### `/gulp-tasks`
- Common Gulp tasks for Development workflow. Do not edit unless you know what you are doing.
-* ### `/gulp-tasks-build`
- Common Gulp tasks for Build workflow. Do not edit unless you know what you are doing.
-* ### `/gulp-tasks-export`
- Common Gulp tasks for Export workflow (compiled and formated bundles). Do not edit unless you know what you are doing.
-* ### `/src`
- Development directory. This is place of developers creativity. Change anything as you wish.
- * `/gfx` — graphic assets
- * `/js` — JavaScripts, all files in this directory will be concatenated into one file; files are sorted by name
- * `/scss`
- * `_variables.scss` — copy from the Bootstrap core for your customization.
- * `bootstrap.scss` — copy from the Bootstrap core for your customization.
- * `c-article.scss` — example of the [BEM component](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#component-namespaces-c-) Article.
- * `custom.scss` — main stlesheet for customization of the project. Contains additions and overriding of the Bootstrap.
- * `u-debugger.scss` — only in Developmnet workflow adds outline and info around HTML element with \[BEM namespaces]\([BEM component](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/). Outlines [objects](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#object-namespaces-o-) `o-`, [component](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#component-namespaces-c-) `c-` and [utilities](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#utility-namespaces-u-) `u-`. To enable functionality set `$show-debugger` to `true` in the file `_variables.scss`.
- * `u-show-grid.scss` — only in Developmnet workflow adds small box into bottom right corner with information about current viewport size accoding to Bootstrap. In the file `_variables.scss` set `$show-grid` to `true` and see bars as Bootstrap grid columns.
- * `/templates`
- * `/pages` — every `*.html` file will be rendered as standalone HTML page on own URL (directory name). Meta attributes passes from according Markdown file in `./content` directory.
- * `/partials` —
- * `layout-default.html` — main layout which extends files in `./templates/pages`
- * `font.list` — tab-delimeted format for [gulp-google-webfonts](https://github.com/battlesnake/gulp-google-webfonts) which download font files and CSS to the project.
-* ### `/static`
- Content of this directory will be coppied into target (temp, export or build directory).
- * `/.well-known/security.txt` — definition of the security policies. [Further info](https://securitytxt.org/)
- * `humans.txt` — detailed public information about project e.g. team members, technologies etc. [Further info](http://humanstxt.org/)
-* ### `/` (root)
- * `.browserslistrc` — [Browserslist](https://github.com/browserslist/browserslist) configuration to share target browsers versions between different front-end tools as Autoprefixer, Babel etc. The configuration is a copy of the Bootstrap configuration in this repo.
- * `.editorconfig` — basic definition of code formatting for different code editors and IDEs. These settings are used as a baseline for language specialised linters in this repo. [Further info](http://editorconfig.org/)
- * `.env.example` — template of the `.env` file, where stored fragments of the code shouldn’t be part of repo’s codebase, e.g. login to FTP.
- * `.eslintignore` — list of the files and directories to be ignore by [Eslint](https://eslint.org/).
- * `.eslintrc.yml` — [Eslint](https://eslint.org/) configuration to specify and configure rules of JavaScript linting. [Further info](https://eslint.org/docs/user-guide/configuring)
- * `.gitattributes` — path-specific settings used by [Git](https://git-scm.com/). Settings that Git applies to certain subdirectories or subsets of files - for example EOL (End Of Line) setting. [Further info](https://git-scm.com/docs/gitattributes)
- * `.gitignore` — list of path-specific pattern to be ignored (not commited) by [Git](https://git-scm.com/). [Further info](https://git-scm.com/docs/gitignore)
- * `.prettierignore` — list of the files and directories to be ignore by [Prettier](https://prettier.io/).
- * `.prettierrc.yml` — [Prettier](https://prettier.io/) configuration to specify and configure rules of language specific code formatting.
- * `.release-it.yml` — [Release It!](https://github.com/release-it/release-it) configuration to specify behaviour of the versioning and package publishing related tasks.
- * `.remarkignore` — list of the files and directories to be ignore by [Remark](https://remark.js.org/).
- * `.remarkrc.yml` — [Remark](https://remark.js.org/) configuration to specify and configure rules of [Markdown](https://daringfireball.net/projects/markdown/) lintng.
- * `.stylelintignore` — list of the files and directories to be ignore by [Stylelint](https://stylelint.io/).
- * `.stylelintrc.yml` — [Stylelint](https://stylelint.io/) configuration to specify and configure rules of CSS (SCSS) linting. See used plugins! [Further info](https://stylelint.io/user-guide/configuration/)
- * `commitlint.config.js` — [commitlint](https://commitlint.js.org/) configuration to help adhering to a commit convention.
- * `gulpconfig.js` — configuration for 🛠️ **development** Gulp file `gulpfile.js`. Contains variables and setting which are specific for Development workflow purposes.
- * `gulpconfig-build.js` — configuration for 💯 **build** Gulp file `gulpfile.build.js`. Contains variables and setting which are specific for Build workflow purposes.
- * `gulpconfig-export.js` — configuration for 👁️ **export** Gulp file `gulpfile.export.js`. Contains variables and setting which are specific for Export workflow purposes.
- * `gulpfile.js` — [Gulp](https://gulpjs.com/) 🛠️ **development** configuration and definition of automation tasks. [Further info](https://www.sitepoint.com/introduction-gulp-js/)
- * `gulpfile.build.js` — [Gulp](https://gulpjs.com/) 💯 **build** configuration and definition of automation tasks. [Further info](https://www.sitepoint.com/introduction-gulp-js/)
- * `gulpfile.export.js` — [Gulp](https://gulpjs.com/) 👁️ **export** configuration and definition of automation tasks. [Further info](https://www.sitepoint.com/introduction-gulp-js/)
- * `CHANGELOG.md` — list of the notable changes in this project.
- * `LICENSE` — Open source license of [Git](https://git-scm.com/) repository. It enables others to freely use, change and distribute the project in the repository. [Further info](https://help.github.com/articles/adding-a-license-to-a-repository/)
- * `package.json` — [NPM](https://www.npmjs.com/) packages specifics. It lists the packages (with their versions) your project depends on. [Further info](https://docs.npmjs.com/files/package.json)
- * `package-lock.json` — [NPM](https://www.npmjs.com/) manifest. Automatically generated with change of `node_modules` or `package.json` if working with NPM. Holds information about which versions of each dependency were installed in order to get consistent installs across machines. [Further info](https://docs.npmjs.com/files/package-lock.json)
- * `README.md` — It’s me!
+* ### `/.github`
+
+ Specialties designed for GitHub.
+
+* ### `/src/routes`
+
+ SvelteKit-style file-based routing system. Each `.md` or `.njk` file becomes a
+ page in the final site. Markdown files are converted to JSON during build and
+ made available in Nunjucks templates.
+
+* ### `/gulp-tasks`
+
+ Common Gulp tasks for Development workflow. Do not edit unless you know what
+ you are doing.
+
+* ### `/src`
+
+ Development directory. This is place of developers creativity. Change anything
+ as you wish.
+
+ * `/gfx` — graphic assets
+ * `/js` — JavaScripts, all files in this directory will be concatenated into
+ one file; files are sorted by name
+ * `/scss`
+ * `_variables.scss` — copy from the Bootstrap core for your customization.
+ * `bootstrap.scss` — copy from the Bootstrap core for your customization.
+ * `c-article.scss` — example of the
+ [BEM component](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#component-namespaces-c-)
+ Article.
+ * `custom.scss` — main stlesheet for customization of the project. Contains
+ additions and overriding of the Bootstrap.
+ * `u-debugger.scss` — only in Developmnet workflow adds outline and info
+ around HTML element with \[BEM
+ namespaces]\([BEM component](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/).
+ Outlines
+ [objects](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#object-namespaces-o-)
+ `o-`,
+ [component](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#component-namespaces-c-)
+ `c-` and
+ [utilities](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#utility-namespaces-u-)
+ `u-`. To enable functionality set `$show-debugger` to `true` in the file
+ `_variables.scss`.
+ * `u-show-grid.scss` — only in Developmnet workflow adds small box into
+ bottom right corner with information about current viewport size accoding
+ to Bootstrap. In the file `_variables.scss` set `$show-grid` to `true` and
+ see bars as Bootstrap grid columns.
+ * `/src/lib/components` — UI components with templates and styles
+ * `/src/config` — Site configuration files
+ * `site.js` — Main site configuration (title, description, meta data)
+
+* `/src/routes` — SvelteKit-style file-based routing
+ * `layout-default.njk` — Main layout template (not rendered as a page)
+ * `index.md` — Homepage content (Markdown with frontmatter)
+ * `index.njk` — Optional Nunjucks template override for homepage
+ * `/about/index.md` — About page content (creates `/about/` route)
+ * `font.list` — tab-delimeted format for
+ [gulp-google-webfonts](https://github.com/battlesnake/gulp-google-webfonts)
+ which download font files and CSS to the project.
+
+* ### `/static`
+
+ Content of this directory will be coppied into target (temp, export or build
+ directory).
+
+ * `/.well-known/security.txt` — definition of the security policies.
+ [Further info](https://securitytxt.org/)
+ * `humans.txt` — detailed public information about project e.g. team members,
+ technologies etc. [Further info](http://humanstxt.org/)
+
+* ### `/` (root)
+ * `.browserslistrc` —
+ [Browserslist](https://github.com/browserslist/browserslist) configuration
+ to share target browsers versions between different front-end tools as
+ Autoprefixer, Babel etc. The configuration is a copy of the Bootstrap
+ configuration in this repo.
+ * `.editorconfig` — basic definition of code formatting for different code
+ editors and IDEs. These settings are used as a baseline for language
+ specialised linters in this repo. [Further info](http://editorconfig.org/)
+ * `.env.example` — template of the `.env` file, where stored fragments of the
+ code shouldn’t be part of repo’s codebase.
+ * `.eslintignore` — list of the files and directories to be ignore by
+ [Eslint](https://eslint.org/).
+ * `.eslintrc.yml` — [Eslint](https://eslint.org/) configuration to specify and
+ configure rules of JavaScript linting.
+ [Further info](https://eslint.org/docs/user-guide/configuring)
+ * `.gitattributes` — path-specific settings used by
+ [Git](https://git-scm.com/). Settings that Git applies to certain
+ subdirectories or subsets of files - for example EOL (End Of Line) setting.
+ [Further info](https://git-scm.com/docs/gitattributes)
+ * `.gitignore` — list of path-specific pattern to be ignored (not commited) by
+ [Git](https://git-scm.com/).
+ [Further info](https://git-scm.com/docs/gitignore)
+ * `.prettierignore` — list of the files and directories to be ignore by
+ [Prettier](https://prettier.io/).
+ * `.prettierrc.yml` — [Prettier](https://prettier.io/) configuration to
+ specify and configure rules of language specific code formatting.
+ * `.release-it.yml` — [Release It!](https://github.com/release-it/release-it)
+ configuration to specify behaviour of the versioning and package publishing
+ related tasks.
+ * `.remarkignore` — list of the files and directories to be ignore by
+ [Remark](https://remark.js.org/).
+ * `.remarkrc.yml` — [Remark](https://remark.js.org/) configuration to specify
+ and configure rules of
+ [Markdown](https://daringfireball.net/projects/markdown/) lintng.
+ * `.stylelintignore` — list of the files and directories to be ignore by
+ [Stylelint](https://stylelint.io/).
+ * `.stylelintrc.yml` — [Stylelint](https://stylelint.io/) configuration to
+ specify and configure rules of CSS (SCSS) linting. See used plugins!
+ [Further info](https://stylelint.io/user-guide/configuration/)
+ * `commitlint.config.js` — [commitlint](https://commitlint.js.org/)
+ configuration to help adhering to a commit convention.
+ * `gulpconfig.js` — configuration for 🛠️ **development** Gulp file
+ `gulpfile.js`. Contains variables and setting which are specific for
+ Development workflow purposes.
+ * `gulpconfig-build.js` — configuration for 💯 **build** Gulp file
+ `gulpfile.build.js`. Contains variables and setting which are specific for
+ Build workflow purposes.
+ * `gulpconfig-export.js` — configuration for 👁️ **export** Gulp file
+ `gulpfile.export.js`. Contains variables and setting which are specific for
+ Export workflow purposes.
+ * `gulpfile.js` — [Gulp](https://gulpjs.com/) 🛠️ **development** configuration
+ and definition of automation tasks.
+ [Further info](https://www.sitepoint.com/introduction-gulp-js/)
+ * `gulpfile.build.js` — [Gulp](https://gulpjs.com/) 💯 **build** configuration
+ and definition of automation tasks.
+ [Further info](https://www.sitepoint.com/introduction-gulp-js/)
+ * `gulpfile.export.js` — [Gulp](https://gulpjs.com/) 👁️ **export**
+ configuration and definition of automation tasks.
+ [Further info](https://www.sitepoint.com/introduction-gulp-js/)
+ * `CHANGELOG.md` — list of the notable changes in this project.
+ * `LICENSE` — Open source license of [Git](https://git-scm.com/) repository.
+ It enables others to freely use, change and distribute the project in the
+ repository.
+ [Further info](https://help.github.com/articles/adding-a-license-to-a-repository/)
+ * `package.json` — [NPM](https://www.npmjs.com/) packages specifics. It lists
+ the packages (with their versions) your project depends on.
+ [Further info](https://docs.npmjs.com/files/package.json)
+ * `package-lock.json` — [NPM](https://www.npmjs.com/) manifest. Automatically
+ generated with change of `node_modules` or `package.json` if working with
+ NPM. Holds information about which versions of each dependency were
+ installed in order to get consistent installs across machines.
+ [Further info](https://docs.npmjs.com/files/package-lock.json)
+ * `README.md` — It’s me!
## Workflow
@@ -198,77 +311,79 @@ When you want to build whole web sites from the data sources as API or many mark
Starts watchers, compilers etc., for development with hot-reload in the browser.
-1. Run development task
+1. Run development task
- ```bash
- npm run dev
- ```
+ ```bash
+ npm run dev
+ ```
-2. Open Browser on URL `http://localhost:4000` or what you see in command-line.
+2. Open Browser on URL `http://localhost:4000` or what you see in command-line.
-3. Modify files in `src` directory a sub-directories.
+3. Modify files in `src` directory a sub-directories.
-4. Changes in the configuration files requires a restart. Stop dev task and run `npm run dev` again.
+4. Changes in the configuration files requires a restart. Stop dev task and run
+ `npm run dev` again.
### Production Build
Produces optimized files in production quality.
-1. Run build task
+1. Run build task
- ```bash
- npm run build
- ```
+ ```bash
+ npm run build
+ ```
-2. See files in `build` directory.
+2. See files in `build` directory.
### Export Build
Produces optimized and formated files with good readability of the code.
-1. Run build task
+1. Run build task
- ```bash
- npm run export
- ```
+ ```bash
+ npm run export
+ ```
-2. See files in `export` directory.
+2. See files in `export` directory.
## Updates from devstack to your existing project
-1. create a branch in your project’s repo (e.g. `devstack-update`)
+1. create a branch in your project’s repo (e.g. `devstack-update`)
- ```bash
- git checkout -b devstack-update
- ```
+ ```bash
+ git checkout -b devstack-update
+ ```
-2. Add this Gulp DevStack as a remote to your project `devstack`
+2. Add this Gulp DevStack as a remote to your project `devstack`
- ```bash
- git remote add devstack git@github.com:cebreus/gulp-devstack.git
- ```
+ ```bash
+ git remote add devstack git@github.com:cebreus/gulp-devstack.git
+ ```
-3. Fetch remote
+3. Fetch remote
- ```bash
- git fetch devstack
- ```
+ ```bash
+ git fetch devstack
+ ```
-4. Merge `devstack-update` to your branch (e.g. `master`) (use `--allow-unrelated-histories` if necessary)
+4. Merge `devstack-update` to your branch (e.g. `master`) (use
+ `--allow-unrelated-histories` if necessary)
- ```bash
- git merge master
- ```
+ ```bash
+ git merge master
+ ```
-5. solve eventual conflicts
+5. solve eventual conflicts
-6. push the devstack-update branch
+6. push the devstack-update branch
- ```bash
- git push -u devstack-update
- ```
+ ```bash
+ git push -u devstack-update
+ ```
-7. create PR from `devstack-update` to your master
+7. create PR from `devstack-update` to your master
## Inject devstack to your new project
@@ -281,21 +396,24 @@ git merge devstack/blankenize --squash --allow-unrelated-histories -X theirs
git commit -m "refactor: Gulp DevStack clean-up"
```
-Don't forget to customize for your project by replacing some strings or deleting files like in section "Optional clenup".
+Don't forget to customize for your project by replacing some strings or deleting
+files like in section "Optional clenup".
## Roadmap and Known issues
-See the [open issues](https://github.com/cebreus/gulp-devstack/issues) for a list of proposed features (and known issues).
+See the [open issues](https://github.com/cebreus/gulp-devstack/issues) for a
+list of proposed features (and known issues).
## Contributing
-Contributions are what makes the open-source community such a fantastic place to learn, inspire, and create. Any contributions you make are **much appreciated**.
+Contributions are what makes the open-source community such a fantastic place to
+learn, inspire, and create. Any contributions you make are **much appreciated**.
-1. Fork the Project
-2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
-3. Commit your changes (\`git commit -m "feat: Add some AmazingFeature")
-4. Push to the branch (`git push origin feature/AmazingFeature`)
-5. Open a Pull Request
+1. Fork the Project
+2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
+3. Commit your changes (\`git commit -m "feat: Add some AmazingFeature")
+4. Push to the branch (`git push origin feature/AmazingFeature`)
+5. Open a Pull Request
## License
@@ -305,4 +423,5 @@ It is distributed under the MIT License. See `LICENSE` for more information.
Jaroslav Vrána — , [web site](https://www.cebre.us/)
-Project Link: [github.com/cebreus/gulp-devstack](https://github.com/cebreus/gulp-devstack)
+Project Link:
+[github.com/cebreus/gulp-devstack](https://github.com/cebreus/gulp-devstack)
diff --git a/REFACTORING_GUIDE.md b/REFACTORING_GUIDE.md
new file mode 100644
index 0000000..b02f9e9
--- /dev/null
+++ b/REFACTORING_GUIDE.md
@@ -0,0 +1,333 @@
+# REFACTORING\_GUIDE.md (Final)
+
+This document is the single source of truth for refactoring the Gulp 5
+development stack.
+
+## 1. Executive Summary (TL;DR)
+
+* **Tech Stack:** Gulp 5, Node.js >=22, pnpm, ES Modules (ESM) only.
+* **JS:** Use `async/await`, `node:test`, and JSDoc for everything. **No
+ CommonJS (`require`) or legacy callbacks.**
+* **CSS Strategy:** This is a hybrid system:
+ 1. **Bootstrap Utilities First:** Use Bootstrap's utility classes (`d-flex`,
+ `p-3`, `text-center`, etc.) for all common styling adjustments.
+ 2. **Custom BEM Components:** Use the `c-` namespace for custom, reusable UI
+ components (`c-card`, `c-hero`).
+ 3. **Custom Utilities (`u-`) as Exceptions:** Use the `u-` namespace **only**
+ for project-specific utilities that Bootstrap does not provide.
+* **Components:** Live in `src/lib/components/`, have their own `.njk`, `.scss`,
+ and `.md` files. Use the `pnpm component:create` CLI.
+* **Core Principle:** Prioritize readability and explicitness. Leverage
+ Bootstrap for speed; create custom components for structure and identity.
+
+## 2. Guiding Principles & Rationale
+
+* **KISS (Keep It Simple, Stupid):** Simple code is easier to read, debug, and
+ maintain.
+* **DRY (Don't Repeat Yourself):** Extract repeated UI patterns into `c-`
+ components and repeated logic into Gulp utils or SCSS mixins.
+* **Why a Hybrid CSS Strategy?** We get the best of both worlds:
+ * **Bootstrap Utilities:** Provide immense speed for layout, spacing, and
+ typography without writing custom CSS. This is our default for "atomic"
+ styling.
+ * **BEM Components (`c-`):** Encapsulate complex, project-specific UI
+ elements. This keeps our HTML clean and semantics meaningful (e.g.,
+ `
` is more descriptive than 20 utility classes).
+ * **Custom Utilities (`u-`):** Serve as a small, controlled set of helpers for
+ needs unique to our project, filling the gaps in Bootstrap's library.
+
+## 3. Project Technology Baseline
+
+* **Gulp:** 5.x (ESM only, async/await patterns)
+* **Node.js:** >=22 (enforced in `package.json`)
+* **Bootstrap:** 5.3+ (Modularly imported for its utility classes and base
+ styles)
+* **SCSS:** Modern SCSS with PostCSS for autoprefixing.
+* **Testing:** `node:test` runner with `node:assert`.
+* **Linting:** ESLint (JS), Stylelint (SCSS), Remark (MD).
+* **Formatting:** Prettier.
+
+## 4. JavaScript & Gulp Task Guidelines
+
+### JS/Gulp Anti-Patterns (To Eliminate)
+
+```javascript
+// ❌ AVOID: Legacy CommonJS, Gulp callbacks, and string-based tasks
+const fs = require('fs')
+function legacyTask(done) {
+ // Manual error handling and done() calls
+ gulp.src('src/**/*.js').on('end', done).on('error', done)
+}
+gulp.task('legacy', legacyTask)
+
+// ❌ AVOID: Unnecessary Promise wrapping
+export async function badPromiseTask() {
+ return new Promise((resolve, reject) => {
+ /* ... */
+ })
+}
+```
+
+### JS/Gulp Best Practices (To Enforce)
+
+```javascript
+// ✅ PREFER: Modern ESM, async/await, and function-based tasks
+import { dest, src } from 'gulp'
+
+import fs from 'node:fs/promises'
+
+/**
+ * Processes source files with proper error handling.
+ * @param {object} options - Task configuration.
+ * @param {string} options.source - Source glob pattern.
+ * @param {string} options.destination - Output directory.
+ * @returns {Promise} Gulp stream.
+ */
+export async function modernTask({ source, destination }) {
+ try {
+ const config = await fs.readFile('./config.json', 'utf8')
+ // Use the config...
+ return src(source).pipe(/* transformations */).pipe(dest(destination))
+ } catch (error) {
+ // Provide context in error messages
+ throw new Error(`modernTask failed: ${error.message}`)
+ }
+}
+```
+
+## 5. SCSS Architecture: The Hybrid Model
+
+This architecture is mandatory. All CSS and HTML must conform to these rules.
+
+### The Utility Class Rule: Bootstrap First
+
+**Always prefer using a built-in Bootstrap utility class over creating a custom
+one.** Before creating a `u-` class, check if Bootstrap already provides a
+solution.
+
+### BEM Namespace Rules
+
+#### `o-` (Object): Structural, unstyled layout patterns.
+
+* **Purpose:** Reusable page structure.
+* **Examples:** `o-container`, `o-grid`.
+* **Rules:** Contains only layout properties. **No colors, backgrounds, or
+ decorative styles.**
+
+#### `c-` (Component): Specific, styled UI elements.
+
+* **Purpose:** Recognizable pieces of the UI.
+* **Examples:** `c-button`, `c-card`, `c-main-nav`.
+* **Rules:** Contains the core, non-utility styling for a component. Uses BEM
+ naming (`c-card__title`, `c-button--primary`).
+
+#### `u-` (Utility): **Custom** single-purpose helper classes.
+
+* **Purpose:** For functionalities **not available in Bootstrap**.
+* **Examples:** `u-text-shadow-heavy`, `u-bg-gradient-animated`.
+* **Rules:** Usually contains one CSS property, often with `!important`. Never
+ create a `u-` class that duplicates a Bootstrap utility.
+
+### SCSS & HTML Examples
+
+#### Correct Class Composition in HTML
+
+```html
+
+
+
+
+
+
+
Card Title
+
+
+ This card uses a custom BEM component for its core styles, but leverages
+ Bootstrap's `border`, `shadow`, `mb-4`, `p-3`, `text-muted`, and `small`
+ utilities for modifications.
+
+
+
+
+```
+
+#### Anti-Patterns (To Eliminate)
+
+```scss
+// ❌ AVOID
+.card .title {
+} // Deep nesting, no BEM
+.button {
+} // No namespace
+.red-text-bold {
+} // Utility class with multiple responsibilities
+
+// ✅ PREFER
+.c-card__title {
+} // BEM
+.c-button {
+} // Component with namespace
+.u-text-red {
+} // Single-purpose utility
+.u-font-bold {
+} // Single-purpose utility
+```
+
+```scss
+// ❌ AVOID: Recreating a utility that Bootstrap already provides.
+.u-text-center {
+ text-align: center !important; /* Bootstrap already has `.text-center` */
+}
+.u-margin-bottom-3 {
+ margin-bottom: 1rem !important; /* Bootstrap already has `.mb-3` */
+}
+
+// ✅ PREFER: Creating a utility only for a custom, project-specific need.
+.u-text-glow {
+ text-shadow: 0 0 8px var(--bs-primary) !important; /* Custom effect not in Bootstrap */
+}
+```
+
+## 6. Component & Template Guidelines
+
+### Component Structure
+
+All reusable components reside in `src/lib/components/` and must follow this
+structure. Use `pnpm component:create` to generate it.
+
+```
+src/lib/components/
+└── card/
+ ├── card.njk # Nunjucks template (must validate data)
+ ├── card.scss # Styles (must start with .c-card)
+ └── card.md # Documentation and data schema
+```
+
+### Nunjucks Template Best Practices
+
+#### Data Passing to Components
+
+**Preferred Method: Use `{% set %}` for variable passing**
+
+```nunjucks
+{# ✅ PREFER: Simple single variable #}
+{% set features = page.features %}
+{% include "components/features/features.njk" %}
+
+{# ✅ PREFER: For multiple variables, use object assignment #}
+{% set cardData = {
+ title: "My Title",
+ content: "My content",
+ modifier: "primary"
+} %}
+{% include "components/card/card.njk" %}
+
+{# ❌ AVOID: Multiple individual variables (verbose and error-prone) #}
+{% set cardTitle = "My Title" %}
+{% set cardContent = "My content" %}
+{% set cardModifier = "primary" %}
+{% include "components/card/card.njk" %}
+```
+
+**Alternative Method: Direct context passing (use sparingly)**
+
+```nunjucks
+{# ⚠️ USE WITH CAUTION: Complex syntax, version-dependent #}
+{% include "components/card/card.njk" with {
+ title: "Card Title",
+ content: "Card content"
+} only %}
+```
+
+#### Why `{% set %}` is Preferred Over `with` Syntax
+
+1. **Syntax Reliability**: `{% set %}` works consistently across all Nunjucks
+ versions
+2. **Readability**: Code is clearer and easier to debug
+3. **Context Issues**: `with { key: value }` creates nested objects that
+ templates may not expect
+4. **Line Break Problems**: `with` syntax is sensitive to line breaks and
+ formatting
+5. **Error Handling**: `{% set %}` provides better error messages when variables
+ don't exist
+
+#### Common Pitfalls with `with` Syntax
+
+```nunjucks
+{# ❌ AVOID: This creates { features: page.features } object #}
+{% include "components/features/features.njk" with { features: page.features } only %}
+
+{# ❌ AVOID: Multi-line with syntax is error-prone #}
+{% include "components/features/features.njk" with {
+ features: page.features
+} only %}
+
+{# ✅ PREFER: Simple variable assignment #}
+{% set features = page.features %}
+{% include "components/features/features.njk" %}
+```
+
+### Template Data and Logic
+
+* **Data Sources:** Global data is in `site`, page-specific data from Markdown
+ frontmatter is in `page`.
+* **Data Validation:** Always validate the existence of data in Nunjucks before
+ rendering it.
+* **Partials:** Extract any repeated Nunjucks blocks into partials.
+
+```nunjucks
+{# ❌ AVOID: Assumes data exists, will error if hero is undefined #}
+
{{ page.hero.title }}
+
+{# ✅ PREFER: Validate data before use #}
+{% if page.hero and page.hero.title %}
+
{{ page.hero.title }}
+{% endif %}
+
+{# ✅ PREFER: Passing data as object to an included component #}
+{% set cardData = {
+ title: "Card Title",
+ content: "Card content here.",
+ htmlClass: "shadow-lg border-primary"
+} %}
+{% include "components/card/card.njk" %}
+
+{# Inside card.njk, you would use the object properties #}
+
+
{{ cardData.title }}
+
{{ cardData.content }}
+
+```
+
+## 7. Refactoring Workflow & Quality Gates
+
+Follow this process for every refactoring task.
+
+### Step 1: Pre-Refactoring Checklist
+
+1. Ensure you are on the latest version of the `main` branch.
+2. Run a full check to confirm a clean starting state:
+ ```bash
+ pnpm format && pnpm js:lint && pnpm css:lint && npm test
+ ```
+3. Create a new branch for your refactoring task.
+
+### Step 2: During Refactoring
+
+1. Make small, incremental changes.
+2. Commit often with clear, descriptive messages (e.g.,
+ `refactor(scss): apply c- namespace to button component`).
+3. Run tests and linters frequently after each significant change.
+
+### Step 3: Post-Refactoring Quality Gates
+
+Before merging, you **must** verify that all gates pass:
+
+| Gate | Command / Action | Status |
+| :----------------- | :-------------------------------------------------------------------------------------------------------------------- | :----- |
+| **Tests Pass** | `npm test` | \[ ] |
+| **Linters Pass** | `pnpm format && pnpm js:lint && pnpm css:lint` | \[ ] |
+| **Builds Succeed** | `npm run build` and `npm run dev` | \[ ] |
+| **No Regressions** | Manually verify key pages/components in a browser. | \[ ] |
+| **CSS Compliant** | **Code prefers Bootstrap utilities.** Custom `u-` classes are rare and justified. `c-` components are used correctly. | \[ ] |
+| **Readability** | The code is demonstrably clearer than before. | \[ ] |
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..76ba178
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,8 @@
+export default {
+ presets: [
+ ['@babel/env', {
+ modules: false,
+ loose: true,
+ }],
+ ],
+}
diff --git a/commitlint.config.js b/commitlint.config.js
index 7bf3352..125c05a 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -1,4 +1,5 @@
-module.exports = {
+// This configuration extends the conventional commit format.
+export default {
extends: ['@commitlint/config-conventional'],
rules: {
'type-case': [2, 'always', ['camel-case', 'lower-case']],
@@ -20,4 +21,4 @@ module.exports = {
],
],
},
-};
+}
diff --git a/content/pages/index.md b/content/pages/index.md
deleted file mode 100644
index 6655298..0000000
--- a/content/pages/index.md
+++ /dev/null
@@ -1,63 +0,0 @@
----
-type: page
-title_h1:
-excerpt:
-hero:
- title: Build static sites, develop with live reload, export optimized sources
- excerpt: Front-end Gulp stack based on Bootsrap for building optimized static pages and exports for collaboration between coders and programmers.
- content: |-
-
-
- Currently **v4.4.0** · All releases
-
- [](https://www.codacy.com/gh/cebreus/gulp-devstack/dashboard?utm_source=github.com\&utm_medium=referral\&utm_content=cebreus/gulp-devstack\&utm_campaign=Badge_Grade)
- 
- 
-
- [](https://github.com/cebreus/gulp-devstack/actions/workflows/github-pages-deploy-pnpm.yml)
- [](https://app.netlify.com/sites/gulp-devstack/deploys)
-entity_status:
- date: 2020-02-01T11:00
- updated_at: 2021-11-21T12:00:00
- workflow_step: publish
-seo:
- title: Front-end Gulp DevStack
- description: Gulp stack for building optimized static pages and exports for collaboration between coders and programmers.
- robots: index,follow
- canonical: 'https://gulp-devstack.cebre.us/'
-open_graph:
- use: true
- type: website
- title: ''
- description: ''
-twitter_cards:
- use: true
- title: ''
- description: ''
----
-
-## Typical use cases
-
-* **Developing** landing pages or prototypes (`npm run dev`).
-* **Exporting** carefully compiled and formated files for collaboration (`npm run export`).
-* **Building** the final (production) bundle, ready for deployment (`npm run deploy`).
-
-When you want to build whole web sites from the data sources as API or many markdown files, go with Static Page Generators (SGC). For example [Gridsome](https://gridsome.org/) (VueJS), [Gatsby](https://www.gatsbyjs.org/) (React) or [Hugo](https://gohugo.io/) (Go) will work for you much better.
-
-## Features
-
-* **SEO-friendly** — Open Graph and Twiter Cards markup, self/canonical.
-* **User-friendly** — image optimizations, favicons, webmanifest and all sources minification to smallest bundle.
-* **Developer-friendly** — [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [Remark](https://remark.js.org/), [Stylelint](https://stylelint.io/) via tasks or with [Husky](https://github.com/typicode/husky) and [Lint staged](https://github.com/okonet/lint-staged).
-* Separate tasks for Development, Export and Build with automatic renaming and hashing all critical assets.
-* Ready for implementation Git based CMS as [Tina CMS](https://tina.io/) or [Netlify CMS](https://www.netlifycms.org/) etc. — Front Matter (Markdown files metadata and content).
-* HTML temlates uses [Nunjucks](https://mozilla.github.io/nunjucks/). Fully customisable [Bootstrap 5.1.x](https://getbootstrap.com/) extended with [BEM](https://en.bem.info/). JavaScript processed with [Babel](https://babeljs.io/) or injected from CDN or as static files.
-
-**Usefull scripts**
-
-* Deploy to FTP (`npm run deploy-ftp`) or Netlify etc.
-* Validating output HTML (`npm run build:validate:html` or `npm run export:validate:html`).
-* Listing all TODO’s (`npm run todo:show`).
diff --git a/content/site.md b/content/site.md
deleted file mode 100644
index 4de2903..0000000
--- a/content/site.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-type: settings
-copyright: Code licensed MIT
-baseUrl: https://gulp-devstack.cebre.us
-meta:
- lang: en
- charset: utf-8
- author: humans.txt
-seo:
- title: 𝕊𝕚𝕥𝕖 SEO Title
- description: 𝕊𝕚𝕥𝕖 SEO Description
- robots: index,follow
- canonical: https://gulp-devstack.cebre.us/
- iclude_to_sitemap: false
-open_graph:
- use: true
- type: website
- app_id: ''
- site_name: Gulp DevStack
- image:
- - /assets/images/gulp-devstack-open-graph.png
- image_text: 𝕊𝕚𝕥𝕖 Open Graph Image Text
-twitter_cards:
- use: false
- type: summary_large_image
- image: []
- site: '@cebreus69'
- creator: '@cebreus69'
----
diff --git a/debug-data-flow.js b/debug-data-flow.js
new file mode 100644
index 0000000..b8e3294
--- /dev/null
+++ b/debug-data-flow.js
@@ -0,0 +1,119 @@
+#!/usr/bin/env node
+import fs from 'fs'
+import { createRequire } from 'module'
+import path from 'path'
+
+const require = createRequire(import.meta.url)
+const matter = require('gray-matter')
+
+/**
+ * Tests the extraction of front matter from a markdown file and checks for related JSON data.
+ */
+function testFrontMatterExtraction() {
+ console.log('=== TESTING FRONT MATTER EXTRACTION ===')
+
+ try {
+ // Load the index markdown file.
+ const indexMdPath = './src/routes/index.md'
+ const mdContent = fs.readFileSync(indexMdPath, 'utf8')
+
+ console.log('\nOriginal Markdown file:')
+ console.log('--------------------------')
+ console.log(mdContent.slice(0, 500) + '...')
+
+ // Extract front matter from the markdown file.
+ const { data, content } = matter(mdContent)
+
+ console.log('\nExtracted Front Matter:')
+ console.log('--------------------------')
+ console.log(JSON.stringify(data, null, 2))
+
+ console.log('\nExtracted Content (first 300 chars):')
+ console.log('--------------------------')
+ console.log(content.slice(0, 300) + '...')
+
+ // Check if the corresponding JSON data file exists.
+ const jsonDataDir = './.tmp/pages'
+ const indexJsonPath = path.join(jsonDataDir, 'index.json')
+
+ console.log('\nChecking if JSON data exists:')
+ console.log('--------------------------')
+ if (fs.existsSync(indexJsonPath)) {
+ const jsonData = JSON.parse(fs.readFileSync(indexJsonPath, 'utf8'))
+ console.log('JSON data exists!')
+ console.log(JSON.stringify(jsonData, null, 2))
+ } else {
+ console.log('JSON data does not exist at:', indexJsonPath)
+
+ // If the JSON file doesn't exist, list the contents of the directory.
+ console.log('\nListing .tmp/pages directory:')
+ console.log('--------------------------')
+ if (fs.existsSync(jsonDataDir)) {
+ fs.readdirSync(jsonDataDir).forEach((file) => {
+ console.log(`- ${file}`)
+ })
+ } else {
+ console.log('Directory does not exist')
+ }
+ }
+ } catch (error) {
+ console.error('Error testing front matter extraction:', error)
+ }
+}
+
+/**
+ * Tests and logs the directory structure and files in the routes directory.
+ */
+function testPaths() {
+ console.log('\n=== TESTING PATHS AND DIRECTORY STRUCTURE ===')
+
+ const routesDir = './src/routes'
+ const tempDir = './.tmp'
+ const datasetDir = path.join(tempDir, 'pages')
+
+ console.log(`Routes source directory: ${routesDir}`)
+ console.log(`Dataset directory: ${datasetDir}`)
+
+ if (!fs.existsSync(routesDir)) {
+ console.error(`Routes directory does not exist: ${routesDir}`)
+ return
+ }
+
+ console.log('\nListing files in routes directory:')
+ console.log('--------------------------')
+ listFilesInDirectory(routesDir)
+}
+
+/**
+ * Recursively lists files and directories in the specified directory.
+ * @param {string} dir - The directory path to list.
+ * @param {string} [indent] - Indentation for nested files/directories.
+ */
+function listFilesInDirectory(dir, indent = '') {
+ const files = fs.readdirSync(dir)
+
+ files.forEach((file) => {
+ const filePath = path.join(dir, file)
+ const stat = fs.statSync(filePath)
+
+ if (stat.isDirectory()) {
+ console.log(`${indent}📁 ${file}/`)
+ listFilesInDirectory(filePath, indent + ' ')
+ } else {
+ console.log(`${indent}📄 ${file}`)
+ }
+ })
+}
+
+// Run the tests.
+testFrontMatterExtraction()
+testPaths()
+
+// Provide a diagnosis based on the test results.
+console.log('\n===== DIAGNOSIS =====')
+console.log(
+ 'If the JSON data does not exist or does not contain the correct metadata, the problem is in dataset-prepare.js'
+)
+console.log(
+ 'If the JSON data is correct but the HTML is missing meta tags, the problem is in html-build.js or in the templates'
+)
diff --git a/docs/COMPONENTS.md b/docs/COMPONENTS.md
new file mode 100644
index 0000000..ae84cd3
--- /dev/null
+++ b/docs/COMPONENTS.md
@@ -0,0 +1,130 @@
+# Components in Nunjucks
+
+Components are reusable Nunjucks partials stored in `src/lib/components/`. Use
+them to keep templates modular and maintainable.
+
+## Usage
+
+Include a component in your template with:
+
+```nunjucks
+{% include "components/card/card.njk" %}
+```
+
+You can pass data to components as variables:
+
+```nunjucks
+{% include "components/card/card.njk" with { title: "Card Title", content: "Text here." } %}
+```
+
+Or set the data in a variable and then include the component:
+
+```nunjucks
+{% set cardData = {
+ title: "Developing",
+ text: "Landing pages or prototypes (npm run dev)."
+} %}
+{% include "components/card/card.njk" with cardData %}
+```
+
+This approach is useful when you want to reuse the same data or pass more
+complex objects to the component.
+
+## Structure
+
+* Each component is a folder in `src/lib/components/` (e.g. `card/`, `header/`)
+* The main file is usually `component-name.njk`
+* Components can have their own assets (images, styles, docs)
+* Typical files:
+ * `component-name.njk` – Nunjucks template
+ * `component-name.scss` – SCSS styles for the component
+ * `component-name.md` – Documentation and usage
+
+## Creating Components
+
+You can create components **manually** or using the CLI utility:
+
+### CLI Utility
+
+The project provides a CLI for component management (see
+`gulp/tasks/component-manager.js`).
+
+* **Create:**
+
+ ```sh
+ pnpm component:create
+ # or
+ npm run component:create
+ ```
+
+ You will be prompted for the component name. The CLI will create a folder with
+ starter files (`.njk`, `.scss`, `.md`).
+
+* **Remove:**
+
+ ```sh
+ pnpm component:remove
+ ```
+
+ Select a component to delete (irreversible).
+
+* **Rename:**
+
+ ```sh
+ pnpm component:rename
+ ```
+
+ Select a component and enter a new name. All files and references in the
+ component will be renamed.
+
+* **List:**
+ ```sh
+ pnpm component:list
+ ```
+ Lists all components and their files.
+
+### Manual Creation
+
+1. Create a folder in `src/lib/components/` (e.g. `my-component/`).
+2. Add a `.njk` template, `.scss` style, and optionally a `.md` doc file.
+3. Follow naming conventions: **kebab-case** for folder and file names.
+
+## SCSS Manifest Generation
+
+All component SCSS files are automatically imported via a generated manifest
+(`_components.scss`). This is handled by the build system
+(`gulp/tasks/sass-components.js`). You do not need to manually import each
+component's SCSS.
+
+## Special/Non-standard Components
+
+Some components are not classic UI blocks, but are used for inserting metadata
+or favicons:
+
+* **favicons**: `favicons/favicons.njk` – contains `` tags for
+ favicons. Included in the page ``.
+* **meta-rich-snippets**: contains templates for SEO and social networks:
+ * `open-graph.njk` – Open Graph meta tags
+ * `seo.njk` – basic SEO meta tags
+ * `twitter-cards.njk` – Twitter Cards meta tags
+
+Usage:
+
+```nunjucks
+{% include "components/favicons/favicons.njk" %}
+{% include "components/meta-rich-snippets/seo.njk" %}
+{% include "components/meta-rich-snippets/open-graph.njk" %}
+{% include "components/meta-rich-snippets/twitter-cards.njk" %}
+```
+
+## Best Practices
+
+* Keep components small and focused
+* Use variables for dynamic content
+* Document expected input in the component file (in `.md` or as a comment in
+ `.njk`)
+* Prefer kebab-case for names
+* Avoid special characters, spaces, or uppercase in names
+
+See [Nunjucks Blocks Documentation](./NUNJUCKS-BLOCKS.md) for block usage in
+layouts.
diff --git a/docs/NUNJUCKS-BLOCKS.md b/docs/NUNJUCKS-BLOCKS.md
new file mode 100644
index 0000000..207b2ce
--- /dev/null
+++ b/docs/NUNJUCKS-BLOCKS.md
@@ -0,0 +1,252 @@
+# Nunjucks Template Blocks Documentation
+
+This document lists all available blocks in the `layout-default.njk` template.
+You can override these blocks in your own templates.
+
+## Block Hierarchy
+
+1. `head_tag` - whole ``
+ * `css` - styles
+ * `head_custom` - custom head tags
+ * `meta_seo` - SEO meta
+ * `favicons` - icons
+ * `meta_og` - Open Graph
+ * `meta_twitter` - Twitter Cards
+2. `body` - whole ``
+ * `header` - header
+ * `hero` - hero section
+ * `main` - main content
+ * `content` - page content
+ * `footer` - footer
+ * `js` - JavaScript files
+ * `scripts` - inline scripts
+
+You can override, extend, or keep any block as needed.
+
+## HTML Structure Blocks
+
+### `{% block head_tag %}`
+
+Overrides the entire `` tag, all code in it.
+
+### `{% block body %}`
+
+Overrides the entire `` tag, including all components.
+
+## Head Section Blocks
+
+### `{% block css %}`
+
+CSS styles. Use `{{ super() }}` to keep default styles.
+
+```njk
+{% block css %}
+ {{ super() }}
+
+{% endblock %}
+```
+
+### `{% block head_custom %}`
+
+Custom tags in the head (e.g. analytics, structured data).
+
+```njk
+{% block head_custom %}
+
+{% endblock %}
+```
+
+### `{% block meta_seo %}`
+
+Basic SEO meta tags (title, description, robots, etc). By default, includes
+`components/meta-rich-snippets/seo.njk`. You can override this block to use your
+own meta tags.
+
+```njk
+{% block meta_seo %}
+ {% include "components/meta-rich-snippets/seo.njk" %}
+{% endblock %}
+```
+
+### `{% block favicons %}`
+
+Favicon links. By default, includes `components/favicons/favicons.njk`. You can
+override this block to use your own favicons.
+
+```njk
+{% block favicons %}
+ {% include "components/favicons/favicons.njk" %}
+{% endblock %}
+```
+
+Or use custom links:
+
+```njk
+{% block favicons %}
+
+
+{% endblock %}
+```
+
+### `{% block meta_og %}`
+
+Open Graph meta tags for social media. By default, includes
+`components/meta-rich-snippets/open-graph.njk`. You can override this block to
+use your own Open Graph tags.
+
+```njk
+{% block meta_og %}
+ {% include "components/meta-rich-snippets/open-graph.njk" %}
+{% endblock %}
+```
+
+### `{% block meta_twitter %}`
+
+Twitter Card meta tags. By default, includes
+`components/meta-rich-snippets/twitter-cards.njk`. You can override this block
+to use your own Twitter meta tags.
+
+```njk
+{% block meta_twitter %}
+ {% include "components/meta-rich-snippets/twitter-cards.njk" %}
+{% endblock %}
+```
+
+## Body Section Blocks
+
+### `{% block header %}`
+
+Main navigation/header component.
+
+```njk
+{% block header %}
+
+
+
+{% endblock %}
+```
+
+### `{% block hero %}`
+
+Hero section (banner, intro). Leave empty to hide.
+
+```njk
+{% block hero %}
+{# empty block #}
+{% endblock %}
+```
+
+or
+
+```njk
+{% block hero %}
+
+
+{% endblock %}
+```
+
+### `{% block footer %}`
+
+Footer component.
+
+```njk
+{% block footer %}
+
+{% endblock %}
+```
+
+### `{% block js %}`
+
+JavaScript files. Use `{{ super() }}` to keep default scripts.
+
+```njk
+{% block js %}
+ {{ super() }}
+
+{% endblock %}
+```
+
+### `{% block scripts %}`
+
+Inline JavaScript.
+
+```njk
+{% block scripts %}
+
+{% endblock %}
+```
+
+## Usage Examples
+
+### Hide a component
+
+```njk
+{% block hero %}
+{% endblock %}
+```
+
+### Keep default content and add your own
+
+```njk
+{% block css %}
+ {{ super() }}
+
+{% endblock %}
+```
+
+### Fully override a component
+
+```njk
+{% block header %}
+
+
+
+{% endblock %}
+```
+
+### Conditional override
+
+```njk
+{% block hero %}
+ {% if page.show_hero %}
+ {{ super() }}
+ {% endif %}
+{% endblock %}
+```
diff --git a/docs/ROUTING.md b/docs/ROUTING.md
new file mode 100644
index 0000000..d72da31
--- /dev/null
+++ b/docs/ROUTING.md
@@ -0,0 +1,80 @@
+# Routing & Template Data
+
+This project uses file-based routing: each file in `/src/routes` becomes a URL
+on the site.
+
+## How Routing Works
+
+* `src/routes/index.md` → `/` (homepage)
+* `src/routes/about/index.md` → `/about/`
+* You can use `.md` (Markdown) for content or `.njk` (Nunjucks) for custom
+ templates
+
+If both `index.md` and `index.njk` exist in the same folder, the `.njk` file is
+used as the template, but all data from the corresponding `.md` file
+(frontmatter and content) is available in the template as variables. This allows
+you to customize layout and logic while keeping content in Markdown.
+
+**Example:**
+
+```
+src/routes/
+├── index.md # → /
+├── index.njk # → / (uses index.njk as template, index.md for data)
+├── about/
+│ ├── index.md # → /about/
+│ └── index.njk # → /about/ (uses index.njk as template, index.md for data)
+```
+
+## Layouts
+
+* Files named `layout-*.njk` (e.g. `layout-default.njk`) are base templates, not
+ pages.
+* Pages use `{% extends "layout-default.njk" %}` to inherit layout structure.
+* Layouts define blocks (see
+ [Nunjucks Blocks Documentation](./NUNJUCKS-BLOCKS.md)) that pages can
+ override.
+* Layouts are not routable URLs themselves.
+
+**Example:**
+
+```nunjucks
+{# src/routes/about/index.njk #}
+{% extends "layout-default.njk" %}
+{% block content %}
+
{{ page.title }}
+
{{ page.description }}
+{% endblock %}
+```
+
+## Data in Templates
+
+* `site` — global config from [`src/config/site.js`](../src/config/site.js)
+* `page` — all frontmatter fields from the current Markdown file
+* Direct variables — top-level frontmatter fields (e.g. `title`, `hero`)
+
+See [Template Data Reference](./TEMPLATE-DATA.md) for details and examples.
+
+## Components
+
+Reusable Nunjucks components are stored in
+[`src/lib/components/`](../src/lib/components/). Include them in templates for
+modular design. See [Components documentation](./COMPONENTS.md) for usage and
+best practices.
+
+## Custom Nunjucks Filters
+
+Custom filters are defined in
+[`gulp/utils/nunjucks-filters.js`](../gulp/utils/nunjucks-filters.js):
+
+* `md` — render Markdown to HTML
+* `dump` — pretty-print objects
+* `safe` — mark as safe HTML
+
+See [Template Data Reference](./TEMPLATE-DATA.md) for usage.
+
+## Template Blocks
+
+You can override any block from the base layout. See
+[Nunjucks Blocks Documentation](./NUNJUCKS-BLOCKS.md) for a full list and usage
+examples.
diff --git a/docs/TEMPLATE-DATA.md b/docs/TEMPLATE-DATA.md
new file mode 100644
index 0000000..77f6f43
--- /dev/null
+++ b/docs/TEMPLATE-DATA.md
@@ -0,0 +1,76 @@
+# Template Data Reference
+
+This project separates data into **site** (global) and **page** (per-page)
+objects for Nunjucks templates.
+
+## Data Sources & Structure
+
+* **Site data**: Global config from
+ [`/src/config/site.js`](../src/config/site.js)
+ * Example structure:
+ ```js
+ export const siteDefaults = {
+ title: 'Gulp DevStack',
+ description: 'Modern frontend development workflow with Gulp',
+ meta: { lang: 'en', charset: 'utf-8' },
+ seo: {
+ /* ... */
+ },
+ }
+ ```
+* **Page data**: Frontmatter in Markdown files under
+ [`/src/routes/`](../src/routes/) (or `/content/pages/`)
+ * Example frontmatter:
+ ```md
+ ---
+ title: Home
+ description: Welcome!
+ menu_main:
+ name: Home
+ order: 1
+ show: true
+ hero:
+ title: ...
+ description: ...
+ content: ...
+ ---
+ ```
+
+## Data Access in Templates
+
+* **`site`**: Global config, always available
+ * `{{ site.title }}`
+ * `{{ site.menu }}`
+ * `{{ site.meta.lang }}`
+* **`page`**: All frontmatter fields for the current page
+ * `{{ page.title }}`
+ * `{{ page.hero.title }}`
+ * `{{ page.features.items }}`
+* **Direct variables**: Top-level frontmatter fields are also available directly
+ * `{{ title }}`
+ * `{{ hero.title }}`
+
+***
+
+## Custom Nunjucks Filters
+
+Custom filters are defined in
+[`gulp/utils/nunjucks-filters.js`](../gulp/utils/nunjucks-filters.js):
+
+* `md` — Render Markdown to HTML
+* `dump` — Pretty-print objects for debugging
+* `safe` — Mark string as safe HTML
+* (See the file for more filters)
+
+Usage example:
+
+```nunjucks
+{{ page.content | md | safe }}
+