Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial release of ThemedProgressPlugin 🌈 #1

Merged
merged 8 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .depcheckrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ignores: [
"rimraf"
]
skip-missing: true
39 changes: 39 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Test

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
name: Test
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16.x, 18.x, 20.x, 22.x]

steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Use Node ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

- name: Install Dependencies
run: yarn install --immutable

- name: Run Tests
run: yarn test --coverage

- name: Run Tests for Compiled Bundles
run: |
yarn build
yarn test:bundles

- name: Depcheck
run: npx depcheck
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,73 @@
[![CodeQL Analysis](https://github.com/01taylop/themed-progress-plugin/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/01taylop/themed-progress-plugin/actions/workflows/codeql-analysis.yml)

A webpack plugin featuring an emoji-themed loading bar for a fun and aesthetic build process.

- [Motivation](#motivation)
- [Example](#example)
- [Usage](#usage)
- [Installation](#installation)
- [Configuration](#configuration)

## Motivation

Traditional compilation processes can often be mundane and provide little visual feedback. `ThemedProgressPlugin` aims to bring a touch of light-hearted fun to everyday coding tasks by introducing a dynamic, emoji-themed loading bar which changes based on the date.

This brings an element of surprise and novelty to the typically routine compilation process, making it a more enjoyable part of the developer's day.

## Example

Normal:

![Progress Bar Normal](https://github.com/01taylop/themed-progress-plugin/blob/main/assets/progress-normal.jpg?raw=true)

During Halloween:

![Progress Bar Themed](https://github.com/01taylop/themed-progress-plugin/blob/main/assets/progress-theme.jpg?raw=true)

## Usage

### Installation

First, install the package as a dependency:

```bash
# Using yarn
yarn add themed-progress-plugin

# Using npm
npm install themed-progress-plugin
```

### Configuration

Configuring `ThemedProgressPlugin` is straightforward. After importing it, you simply need to add it to the plugins array in your webpack configuration.

You can import `ThemedProgressPlugin` using either CommonJS or ES Modules. Here's an example of how to do this:

For CommonJS:

```js
const { ThemedProgressPlugin } = require('themed-progress-plugin')

module.exports = {
// other webpack configuration...
plugins: [
new ThemedProgressPlugin(),
// other plugins...
],
}
```

For ES Modules:

```js
import { ThemedProgressPlugin } from 'themed-progress-plugin'

export default {
// other webpack configuration...
plugins: [
new ThemedProgressPlugin(),
// other plugins...
],
}
```
Binary file added assets/progress-normal.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/progress-theme.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"presets": [
["@babel/preset-env", { "targets": { "node": "current" } }]
],
"env": {
"cjs": {
"presets": [["@babel/preset-env", { "modules": "commonjs" }]],
"plugins": [
["babel-plugin-add-import-extension", { "extension": "cjs" }]
]
},
"esm": {
"presets": [["@babel/preset-env", { "modules": false }]],
"plugins": [
["babel-plugin-add-import-extension", { "extension": "js" }]
]
}
}
}
16 changes: 16 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default {
clearMocks: true,
collectCoverageFrom: [
'src/**/*.js',
],
coverageDirectory: 'coverage',
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
testMatch: ['**/*.spec.js'],
}
10 changes: 10 additions & 0 deletions jest/cjs.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import baseConfig from '../jest.config.js'

export default {
...baseConfig,
moduleNameMapper: {
'<rootDir>/src/config$': '<rootDir>/lib/config.cjs',
'<rootDir>/src/index$': '<rootDir>/lib/index.cjs',
},
rootDir: '../',
}
10 changes: 10 additions & 0 deletions jest/esm.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import baseConfig from '../jest.config.js'

export default {
...baseConfig,
moduleNameMapper: {
'<rootDir>/src/config$': '<rootDir>/lib/config.js',
'<rootDir>/src/index$': '<rootDir>/lib/index.js',
},
rootDir: '../',
}
40 changes: 34 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,52 @@
{
"name": "themed-progress-plugin",
"description": "A webpack plugin featuring an emoji-themed loading bar for a fun and aesthetic build process.",
"description": "A Webpack plugin featuring an emoji-themed loading bar for a fun and aesthetic build process.",
"repository": {
"type": "git",
"url": "https://github.com/01taylop/themed-progress-plugin"
},
"version": "0.0.1",
"version": "1.0.0",
"type": "module",
"main": "./lib/index.js",
"exports": {
".": {
"import": "./lib/index.js",
"require": "./lib/index.cjs"
}
},
"files": [
"lib"
],
"scripts": {
"build:cjs": "babel src -d lib --env-name cjs --out-file-extension .cjs",
"build:esm": "babel src -d lib --env-name esm --out-file-extension .js",
"build": "rimraf lib && yarn run build:cjs && yarn run build:esm",
"prepublishOnly": "yarn test --coverage && yarn build && yarn test:bundles",
"test": "jest",
"test:bundles": "jest --config ./jest/cjs.config.js && jest --config ./jest/esm.config.js"
},
"peerDependencies": {
"webpack": "^5.0.0"
},
"dependencies": {
"chalk": "4.1.2"
},
"devDependencies": {
"@babel/cli": "7.24.6",
"@babel/core": "7.24.6",
"@babel/preset-env": "7.24.6",
"babel-plugin-add-import-extension": "1.6.0",
"jest": "29.7.0",
"rimraf": "5.0.7",
"webpack": "5.91.0"
},
"author": "Patrick Taylor <[email protected]>",
"keywords": [
"emoji",
"loading",
"plugin",
"progress",
"progress-plugin",
"themed-progress-plugin",
"webpack",
"webpack-plugin"
"themed",
"webpack"
]
}
48 changes: 48 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import chalk from 'chalk'

const dateConfigurations = {
'01-01': ['🎉', '⬜️'], // New Year's Day
'02-14': ['🌹', '🥀'], // Valentine's Day
'03-17': ['🍀', '⬜️'], // St Patrick's Day
'04-01': ['🃏', '⬜️'], // April Fool's Day
'04-10-2025_04-20-2025': ['🐣', '🥚'], // Easter 2024
'04-22': ['🌎', '⬜️'], // Earth Day
'06-05': ['🌳', '⬜️'], // World Environment Day
'06-08': ['🌊', '⬜️'], // World Oceans Day
'06-19_06-23': ['☀️', '☁️'], // Summer Solstice (21st June)
'07-04': ['🎆', '⬜️'], // Independence Day (US)
'07-01-2024_07-14-2024': ['🎾', '⬜️'], // Wimbledon 2024 (UK)
'09-05': ['💖', '🤍'], // International Charity Day
'10-01': ['☕️', '⬜️'], // International Coffee Day
'10-24_10-31': ['🎃', '🦇'], // Halloween
'12-01_12-31': ['⛄️', '🧊'], // Winter
}

const getProgressConfig = () => {
const currentDate = new Date()
const today = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()).getTime()

const matchingConfig = Object.entries(dateConfigurations).find(([dateRange]) => {
const [startDateString, endDateString] = dateRange.split('_')

const [startMonth, startDay, startYear = currentDate.getFullYear()] = startDateString.split('-').map(Number)
const startDate = new Date(startYear, startMonth - 1, startDay).getTime()

if (!endDateString) {
return startDate === today
}

const [endMonth, endDay, endYear = currentDate.getFullYear()] = endDateString.split('-').map(Number)
const endDate = new Date(endYear, endMonth - 1, endDay).getTime()

return startDate <= today && endDate >= today
})

return matchingConfig
? [matchingConfig[1], 20].flat()
: [chalk.green('\u2588'), chalk.bgWhite(' '), 40]
}

export {
getProgressConfig,
}
38 changes: 38 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import readline from 'readline'
import { ProgressPlugin } from 'webpack'

import { getProgressConfig } from './config'

class ThemedProgressPlugin {
constructor() {
this.progressConfig = getProgressConfig()
this.progressPlugin = new ProgressPlugin(this.handler.bind(this))
}

handler(...args) {
this.progress(...args)
}

progress(percentage, message) {
const [startChar, endChar, progressLength] = this.progressConfig

const percent = (percentage * 100).toFixed()
const segments = Math.floor(progressLength * percentage)
const emptySegments = progressLength - segments

const complete = startChar.repeat(segments)
const incomplete = endChar.repeat(emptySegments)

readline.clearLine(process.stdout, 0)
readline.cursorTo(process.stdout, 0)
process.stdout.write(`${complete}${incomplete} | ${percent}% ${message}`)
}

apply(compiler) {
return this.progressPlugin.apply(compiler)
}
}

export {
ThemedProgressPlugin,
}
41 changes: 41 additions & 0 deletions tests/config.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import chalk from 'chalk'

import { getProgressConfig } from '../src/config'

jest.mock('chalk', () => ({
bgWhite: jest.fn().mockImplementation(text => text),
green: jest.fn().mockImplementation(text => text),
}))

describe('getProgressConfig', () => {

test.each([
['2025-01-01', ['🎉', '⬜️', 20]],
['2025-01-02', ['\u2588', ' ', 40]],
['2025-02-14', ['🌹', '🥀', 20]],
['2025-03-17', ['🍀', '⬜️', 20]],
['2025-04-10', ['🐣', '🥚', 20]],
['2025-04-20', ['🐣', '🥚', 20]],
['2025-04-22', ['🌎', '⬜️', 20]],
['2025-06-05', ['🌳', '⬜️', 20]],
['2025-06-08', ['🌊', '⬜️', 20]],
['2025-06-19', ['☀️', '☁️', 20]],
['2025-06-23', ['☀️', '☁️', 20]],
['2025-07-04', ['🎆', '⬜️', 20]],
['2024-07-01', ['🎾', '⬜️', 20]],
['2024-07-14', ['🎾', '⬜️', 20]],
['2025-09-05', ['💖', '🤍', 20]],
['2025-10-01', ['☕️', '⬜️', 20]],
['2025-10-24', ['🎃', '🦇', 20]],
['2025-10-31', ['🎃', '🦇', 20]],
['2025-12-01', ['⛄️', '🧊', 20]],
['2025-12-31', ['⛄️', '🧊', 20]],
])('returns the correct configuration for %s', (date, expectedResult) => {
jest.useFakeTimers().setSystemTime(new Date(date))

const config = getProgressConfig()

expect(config).toEqual(expectedResult)
})

})
Loading
Loading