CSS-Deduplication part 2 (CSS 중복제거 플러그인 제작)
이전 포스팅을 통해 postcss 커스텀 스크립트로 CSS 중복을 제거하는 방법을 확인할 수 있습니다.
이번 포스팅에서는 media 쿼리에 대한 처리 로직을 추가하고 postcss 플러그인으로 제작해 보도록 하겠습니다. 다음 포스팅을 통해 완성된 플러그인을 npmjs.org 사이트를 통해 배포하고 npm i 명령어로 설치가 가능하게 만들어 보겠습니다.
Abstract
- postcss 커스텀 스크립트 개선(media 쿼리 처리 로직 추가)
- npm 패키지로 배포 가능한 플러그인으로 제작
커스텀 스크립트 개선
중복제거 커스텀 스크립트는 selector 기반으로 작업을 수행하는데 @media 쿼리에 대해서는 중복제거를 수행하지 못하고 있습니다. @가 붙은 atrule 에 대해서도 처리가 가능하도록 스크립트를 개선하겠습니다.
스크립트 개선
postcss.config.js 파일을 아래와 같이 수정합니다.
postcss 코드 기술 방법에 대해서는 API 문서 의 내용을 참고하여 작성하면 됩니다.
const postcss = require("postcss");
module.exports = {
plugins: [customMerge({})],
};
// custom-clean plugin to keep only the first declaration of each rule
function customMerge(options) {
return {
postcssPlugin: "postcss-delete-duplicate-selector",
Once(root, { result }) {
const filteredRules = new Map();
root.walk((node) => {
// Check if the node is a rule and not an at-rule and parent type is root
if (node.type === "rule" && node.parent.type === "root") {
const selector = node.selector;
if (!filteredRules.has(selector)) {
filteredRules.set(selector, node);
}
} else if (node.type === "atrule") {
const mediaRule = postcss.atRule({
name: node.name,
params: node.params,
});
node.nodes.forEach((rule) => {
const clonedRule = rule.clone();
mediaRule.append(clonedRule);
});
filteredRules.set(mediaRule.toString(), mediaRule);
}
});
root.removeAll();
filteredRules.forEach((rule, index) => {
root.append(rule);
});
},
};
}
npm run build
명령어를 수행하여 atrule 에 대해서도 잘 처리가 되는지 확인합니다.
플러그인 코드 작성
동작이 잘 되는것을 확인했으면 이를 플러그인 형태로 제작하도록 하겠습니다. 플러그인의 이름은 postcss-delete-duplicate-selector 로 하겠습니다.
node_modules 디렉토리 하위에 postcss-delete-duplicate-selector 디렉토리를 생성합니다.
디렉토리의 전체 구조는 다음과 같습니다.
node_modules/potcss-delete-duplicate-selector/
src 디렉토리에 index.js 파일을 다음과 같이 생성합니다.
node_modules/potcss-delete-duplicate-selector/src/index.js
const postcss = require("postcss");
const plugin = (opts = {}) => {
return {
postcssPlugin: "postcss-delete-duplicate-selector",
Once(root, { result }) {
const filteredRules = new Map();
root.walk((node) => {
// Check if the node is a rule and not an at-rule and parent type is root
if (node.type === "rule" && node.parent.type === "root") {
const selector = node.selector;
if (!filteredRules.has(selector)) {
filteredRules.set(selector, node);
}
} else if (node.type === "atrule") {
const mediaRule = postcss.atRule({
name: node.name,
params: node.params,
});
node.nodes.forEach((rule) => {
const clonedRule = rule.clone();
mediaRule.append(clonedRule);
});
filteredRules.set(mediaRule.toString(), mediaRule);
}
});
root.removeAll();
filteredRules.forEach((rule, index) => {
root.append(rule);
});
},
};
};
plugin.postcss = true;
module.exports = plugin;
module.exports 를 이용하여 외부 참조가 가능하도록 코드를 작성해줍니다.
package.json 파일은 다음과 같이 작성합니다.
node_modules/potcss-delete-duplicate-selector/package.json
{
"name": "postcss-delete-duplicate-selector",
"version": "1.0.0",
"description": "PostCSS plugin delete duplicate css selector in the file",
"main": "src/index.js",
"keywords": [
"postcss",
"css",
"postcss-plugin",
"delete",
"duplicate",
"selector",
"Deduplication"
],
"author": "hwantage <hwantagexsw2@gmail.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/hwantage/postcss-delete-duplicate-selector.git"
},
"engines": {
"node": ">=18.15.0"
},
"peerDependencies": {
"postcss": "^8.4.32"
},
"devDependencies": {
"postcss": "^8.4.32"
}
}
“main” 항목이 entry 소스 경로가 됩니다. 우리는 src 디렉토리 하위에 코드를 작성했기 때문에 src/index.js 로 작성합니다.
“version"의 경우 1.0.0 부터 작성을 하시면 됩니다.
프로젝트 루트의 postcss.config.js 파일을 다음과 같이 변경합니다.
/postcss.config.js
module.exports = {
plugins: [require("postcss-delete-duplicate-selector")],
};
기존의 커스텀 함수 코드를 제거하고 node_modules 에 작성된 플러그인을 참조하도록 변경하였습니다.
npm run build 를 수행하여 node_modules 하위에 생성한 플러그인 코드를 통해 CSS 중복 제거가 잘 수행되는지 확인합니다.
여기까지 하면 postcss 를 통해 플러그인 생성 준비를 완료했습니다.
작성된 플러그인을 npm 패키지에 등록하여 오픈소스 생태계에 기여하는 방법에 대해 다음 포스팅에서 설명하겠습니다.