Skip to content

Commit

Permalink
Merge pull request #37 from vordgi/ncm-36
Browse files Browse the repository at this point in the history
ncm-36 update the configuration and its validation
  • Loading branch information
vordgi authored Jan 17, 2024
2 parents ec96b49 + de01169 commit 474e185
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 55 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

Library for configuring style _(css/scss/sass)_ modules to generate compressed classes (`.header` -> `.a`, `.nav` -> `.b`, ..., `.footer` -> `.aad`, etc.) with support for changes and rebuilding without clearing the built application.

### **Important**
**This description is for `>=2.2.0`. See instructions for previous versions at [next-classnames-minifier/tree/2.1.1](https://github.com/vordgi/next-classnames-minifier/tree/2.1.1)**

## Reasons
*Compressing classes* can reduce the size of the generated html and css by up to *20%*, which will have a positive effect on page rendering and metrics (primarily [FCP](https://web.dev/first-contentful-paint/))

Expand All @@ -27,7 +30,7 @@ Create `next.config.js` file in your project and apply the library.
```js
const withClassnamesMinifier = require('next-classnames-minifier').default;

module.exports = withClassnamesMinifier()({
module.exports = withClassnamesMinifier({ type: process.env.NODE_ENV === 'development' ? 'none' : 'minified' })({
// next.js config
});
```
Expand All @@ -38,11 +41,12 @@ const withClassnamesMinifier = require('next-classnames-minifier').default;
const withPlugins = require('next-compose-plugins');

module.exports = withPlugins([
[withClassnamesMinifier()]
[withClassnamesMinifier({ type: process.env.NODE_ENV === 'development' ? 'none' : 'minified' })]
], nextConfig);
```

## Configuration

next-classname-minifier has 3 types of changing classnames:

* minified — the main option. It is not recommended to use this option in development mode, it may slow down the update;
Expand All @@ -54,14 +58,14 @@ You can choose different options for development and production.
Configuration example:
```js
module.exports = withPlugins([
[withClassnamesMinifier({ dev: 'none', prod: 'minified' })]
[withClassnamesMinifier({ type: process.env.NODE_ENV === 'development' ? 'none' : 'minified' })]
], nextConfig);
```

Custom mode example:
```js
module.exports = withPlugins([
[withClassnamesMinifier({ dev: { type: 'custom', templateString: '[path][name]__[local]_[hash:base64:5]' }, prod: 'minified' })]
[withClassnamesMinifier({ type: 'custom', templateString: '[path][name]__[local]_[hash:base64:5]' })]
], nextConfig);
```

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-classnames-minifier",
"version": "2.1.1",
"version": "2.2.0",
"description": "Library for configuring style modules to generate compressed classes",
"main": "dist/withClassnamesMinifier.js",
"types": "dist/withClassnamesMinifier.d.ts",
Expand Down
9 changes: 5 additions & 4 deletions src/lib/types/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { VALID_MINIFIERS_KEYS, CUSTOM, MINIFIED, NONE } from '../constants/minifiers';
import { VALID_MINIFIERS_KEYS } from '../constants/minifiers';
import type BaseConverter from '../converters/ConverterBase';

export type MINIFIER_KEY = typeof VALID_MINIFIERS_KEYS;
export type Config = typeof MINIFIED | typeof NONE | { type: typeof CUSTOM, templateString: string };
export type Options = { dev?: Config, prod?: Config };
export type Config = {
type?: (typeof VALID_MINIFIERS_KEYS)[number];
templateString?: string;
}

export type InjectConfig = {
localIdentName?: string, classnamesMinifier: BaseConverter
Expand Down
44 changes: 44 additions & 0 deletions src/lib/validateConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { CUSTOM, VALID_MINIFIERS_KEYS } from "./constants/minifiers";

type Config = {
type?: (typeof VALID_MINIFIERS_KEYS)[number];
templateString?: string;
}

const validKeys = ['type', 'templateString'];

const validateIsObject = (config: unknown): config is Config => {
if (!config) return false;

if (typeof config !== 'object' || Array.isArray(config)) {
console.error(`next-classnames-minifier: Invalid configuration. Expected object, received ${typeof config}. See https://github.com/vordgi/next-classnames-minifier#configuration`);
process.exit();
}

const isValidKeys = Object.keys(config).every(key => validKeys.includes(key));

if (!isValidKeys) {
console.error(`next-classnames-minifier: Invalid configuration. Valid keys are: ${validKeys.join(', ')}. See https://github.com/vordgi/next-classnames-minifier#configuration`);
process.exit();
}

return true;
}

const validateConfig = (config: unknown = {}): Config => {
if (!validateIsObject(config)) return {};

if (config.type && !VALID_MINIFIERS_KEYS.includes(config.type)) {
console.error(`next-classnames-minifier: Invalid configuration. Valid types are: ${VALID_MINIFIERS_KEYS.join(', ')}. See https://github.com/vordgi/next-classnames-minifier#configuration`)
process.exit();
}

if (config.type === CUSTOM && !config.templateString) {
console.error('next-classnames-minifier: Invalid configuration. The templateString option is required for the "custom" type. See https://github.com/vordgi/next-classnames-minifier#configuration')
process.exit();
}

return config;
}

export default validateConfig;
74 changes: 30 additions & 44 deletions src/withClassnamesMinifier.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,45 @@
import type { Configuration } from 'webpack/types';
import type { Options } from './lib/types/plugin';
import type { Config } from './lib/types/plugin';
import type ConverterBase from './lib/converters/ConverterBase';
import { CUSTOM, MINIFIED, VALID_MINIFIERS_KEYS } from './lib/constants/minifiers';
import { CUSTOM, MINIFIED } from './lib/constants/minifiers';
import ConverterMinified from './lib/converters/ConverterMinified';
import ConverterCustom from './lib/converters/ConverterCustom';
import injectConfig from './lib/injectConfig';
import validateConfig from './lib/validateConfig';
import path from 'path';

let classnamesMinifier: ConverterBase;
let infoMessageShown = false;

const withClassnameMinifier = (pluginOptions: Options = {}) => (nextConfig: any = {}) => ({
...nextConfig,
webpack: (config: Configuration, options: any) => {
const { dev = 'none', prod = 'minified' } = pluginOptions;
const isProd = process.env.NODE_ENV === 'production';
const minifierConfig = isProd ? prod : dev;
const minifierType = typeof minifierConfig === 'string' ? minifierConfig : minifierConfig.type;

if (!infoMessageShown) {
if (!VALID_MINIFIERS_KEYS.includes(minifierType)) {
console.log(`next-classnames-minifier. Invalid key for target env: ${minifierType}, valid keys are: ${VALID_MINIFIERS_KEYS.join(', ')}`);
process.kill(0);
process.exit();
} else if (!isProd && minifierType === MINIFIED) {
console.log(`next-classnames-minifier. It is not recommended to use "minified" mode in development mode, it may slow down the update`);
} else if (minifierType === 'custom' && (typeof minifierConfig !== 'object' || !minifierConfig.templateString)) {
console.log(`next-classnames-minifier. Add templateString for custom minifier`);
process.kill(0);
process.exit();
}
infoMessageShown = true;
}

if (minifierType === MINIFIED) {
if (!classnamesMinifier) {
const cacheDir = path.join(process.cwd(), '.next/cache/ncm');
classnamesMinifier = new ConverterMinified(cacheDir);
}

injectConfig({ classnamesMinifier }, config.module?.rules);
} else if (minifierType === CUSTOM && typeof minifierConfig === 'object' && minifierConfig.templateString) {
if (!classnamesMinifier) {
classnamesMinifier = new ConverterCustom();
const withClassnameMinifier = (pluginOptions: Config = {}) => {
validateConfig(pluginOptions);

return (nextConfig: any = {}) => ({
...nextConfig,
webpack: (config: Configuration, options: any) => {
const { type = MINIFIED, templateString } = pluginOptions;

if (type === MINIFIED) {
if (!classnamesMinifier) {
const cacheDir = path.join(process.cwd(), '.next/cache/ncm');
classnamesMinifier = new ConverterMinified(cacheDir);
}

injectConfig({ classnamesMinifier }, config.module?.rules);
} else if (type === CUSTOM && templateString) {
if (!classnamesMinifier) {
classnamesMinifier = new ConverterCustom();
}

injectConfig({ localIdentName: templateString, classnamesMinifier }, config.module?.rules);
}

injectConfig({ localIdentName: minifierConfig.templateString, classnamesMinifier }, config.module?.rules);
}
if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, options);
}

if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, options);
return config;
}

return config;
}
});
})
};

export default withClassnameMinifier;

0 comments on commit 474e185

Please sign in to comment.