CSS الأصلي
يوضح هذا الدليل كيفية استخدام معالجة CSS المدمجة في webpack عبر experiments.css، وكيفية نقل إعداد قائم من css-loader وstyle-loader وmini-css-extract-plugin إلى الحل الأصلي.
البدء
فعّل دعم CSS الأصلي في ملف تخصيص webpack:
webpack.config.js
export default {
experiments: {
css: true,
},
};عند تفعيل هذا الخيار، يتعامل webpack مع ملفات .css بوصفها وحدات أصلية: يحلل @import وurl()، ويستخرج أوراق الأنماط، وينشئ تجزئات للمحتوى، ويدعم CSS Modules، وكل ذلك من دون css-loader أو style-loader أو mini-css-extract-plugin.
استيراد CSS
بعد تفعيل الميزة التجريبية، استورد ملفات .css مباشرةً من JavaScript:
src/index.js
import "./styles.css";
const element = document.createElement("h1");
element.textContent = "Hello native CSS";
document.body.appendChild(element);src/styles.css
h1 {
color: #1f6feb;
}يعالج webpack ملف CSS ويضمه إلى مخرجات البناء.
أنواع وحدات CSS
يضيف CSS الأصلي أربع قيم للخيار Rule.type. معرفة النوع المناسب أساسية عند الترحيل، لأن كل نوع يقابل وضعًا مختلفًا من modules.mode في css-loader:
| النوع | نطاق الأسماء | ما يقابله في css-loader |
|---|---|---|
css | عام، من دون تحليل CSS Modules | modules: false |
css/global | المحددات عامة، مع احترام :local() | modules.mode: 'global' |
css/module | محلي افتراضيًا، وتتيح :global() الخروج إلى النطاق العام | modules.mode: 'local' |
css/auto | يختار css/module لملفات *.module.css و*.modules.css، وإلا css/global | modules.auto: true |
القاعدة الافتراضية التي يضيفها webpack للنمط /\.css$/i هي css/auto. لذلك تصبح ملفات *.module.css وحدات CSS، بينما تبقى بقية الملفات عامة، وهو ما يطابق الإعداد الأكثر شيوعًا في css-loader من دون تخصيص إضافي.
CSS Modules
عند استخدام css/auto، سمِّ الملف *.module.css أو *.modules.css لتفعيل CSS Modules له:
src/button.module.css
.button {
background: #0d6efd;
color: white;
border: 0;
border-radius: 4px;
padding: 8px 12px;
}src/index.js
import * as styles from "./button.module.css";
const button = document.createElement("button");
button.className = styles.button;
button.textContent = "Click me";
document.body.appendChild(button);يمكنك تخصيص سلوك CSS Modules عبر خيارات المحلل والمولد. راجع قسم جميع الخيارات مع أمثلة أدناه:
webpack.config.js
export default {
experiments: {
css: true,
},
module: {
parser: {
"css/auto": {
namedExports: true,
},
},
generator: {
"css/auto": {
exportsConvention: "camel-case-only",
localIdentName: "[uniqueName]-[id]-[local]",
},
},
},
};ميزات CSS Modules المدعومة
يدعم CSS Modules الأصلي ميزات التأليف نفسها الموجودة في css-loader، لذا يمكن نقل معظم أوراق الأنماط من دون تعديل:
composes— تركيب صنف محلي من صنف آخر، بما في ذلكcomposes: foo from "./other.module.css". تكون القيمة المصدّرة قائمة أسماء الأصناف مفصولة بمسافات.@value— تعريف قيم قابلة لإعادة الاستخدام واستيرادها، مثل@value primary: #1f6feb;و@value primary from "./vars.module.css".:export— تصدير أزواج مفاتيح وقيم مخصصة إلى JavaScript.:local()و:global()— تبديل نطاق الأسماء داخل أي نوع من الوحدات.
/* button.module.css */
@value brand: #1f6feb;
.base {
padding: 8px 12px;
}
.primary {
composes: base;
background: brand;
}
:export {
brandColor: brand;
}أوضاع الإخراج (exportType)
يمكن إخراج وحدة CSS واحدة بأربع طرائق. يحدد خيار المحلل exportType الطريقة المستخدمة، وكل واحدة منها تحل محل جزء مختلف من سلسلة الأدوات التقليدية:
exportType | السلوك | يحل محل |
|---|---|---|
"link" (الافتراضي) | استخراج ملف .css وتحميله عبر <link> | mini-css-extract-plugin |
"style" | حقن عنصر <style> من شيفرة runtime | style-loader |
"text" | تصدير CSS كسلسلة نصية | css-loader مع exportType: 'string' |
"css-style-sheet" | تصدير كائن CSSStyleSheet قابل للإنشاء | css-loader مع exportType: 'css-style-sheet' |
يمكنك ضبطه لجميع الملفات التابعة لنوع وحدة معين:
export default {
experiments: { css: true },
module: {
parser: {
"css/auto": {
exportType: "style",
},
},
},
};أو ضمن قاعدة تطبق على مجموعة فرعية من الملفات:
export default {
experiments: { css: true },
module: {
rules: [
{
test: /\.css$/i,
type: "css/auto",
parser: { exportType: "style" },
},
],
},
};دليل الترحيل
نظرة سريعة
| الإعداد التقليدي | البديل الأصلي |
|---|---|
mini-css-extract-plugin (MiniCssExtractPlugin.loader) | الاستخراج المدمج (القيمة الافتراضية exportType: "link") |
MiniCssExtractPlugin وخيارا filename وchunkFilename | output.cssFilename وoutput.cssChunkFilename |
style-loader | exportType: "style" |
css-loader | تحليل CSS المدمج، ولا حاجة إلى loader |
css-loader وخيارا url وimport | module.parser.css.url وimport، وكلاهما true افتراضيًا |
اكتشاف css-loader التلقائي لـmodules | نوع الوحدة css/auto |
css-loader وخيار modules.mode | النوعان css/module وcss/global مع pure |
css-loader وخيار modules.localIdentName | خيار المولد localIdentName |
css-loader وخيار modules.exportLocalsConvention | خيار المولد exportsConvention |
css-loader وخيار modules.namedExport | module.parser.css.namedExports، وقيمته الافتراضية true |
css-loader وخيار modules.exportOnlyLocals | خيار المولد exportsOnly |
css-loader وخيار esModule | خيار المولد esModule، وقيمته الافتراضية true |
css-loader مع exportType: 'string' أو 'css-style-sheet' | exportType: "text" أو"css-style-sheet" |
انقل loader واحدًا في كل خطوة. رُتبت الأقسام التالية بحيث يبقى البناء سليمًا في أثناء الترحيل.
1. ابدأ من إعداد تقليدي
webpack.config.js
import MiniCssExtractPlugin from "mini-css-extract-plugin";
export default {
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [new MiniCssExtractPlugin()],
};2. فعّل CSS الأصلي
webpack.config.js
export default {
experiments: {
css: true,
},
};تتولى الآن القاعدة المدمجة /\.css$/i ← css/auto معالجة استيرادات .css. احذف القاعدة والملحق المخصصين بعد التأكد في الأقسام التالية من وجود بديل لكل خيار تعتمد عليه.
3. استبدل mini-css-extract-plugin
يستخرج CSS الأصلي أوراق الأنماط ويضيف إليها تجزئات المحتوى افتراضيًا (exportType: "link")، لذلك لم تعد بحاجة إلى الملحق أو loader الخاص به:
webpack.config.js
-import MiniCssExtractPlugin from "mini-css-extract-plugin";
-
export default {
+ experiments: {
+ css: true,
+ },
- module: {
- rules: [
- {
- test: /\.css$/i,
- use: [MiniCssExtractPlugin.loader, "css-loader"],
- },
- ],
- },
- plugins: [new MiniCssExtractPlugin()],
};انقل بقية خيارات الملحق إلى البدائل التالية:
خيار mini-css-extract-plugin | البديل الأصلي |
|---|---|
filename | output.cssFilename |
chunkFilename | output.cssChunkFilename |
خيار loader المسمى publicPath | output.publicPath |
خيار loader المسمى esModule | خيار المولد esModule، وافتراضيًا true |
ignoreOrder | لا يوجد؛ CSS الأصلي لا يصدر تحذيرات تعارض ترتيب |
webpack.config.js
export default {
experiments: { css: true },
output: {
cssFilename: "[name].[contenthash].css",
cssChunkFilename: "[id].[contenthash].css",
},
};4. استبدل css-loader
لمعظم خيارات css-loader مقابل أصلي ضمن module.parser.css وmodule.generator.css. وتطابق القيم الافتراضية الشائعة، مثل تفعيل url وimport وnamedExports، إعداد css-loader المعتاد؛ لذلك لا تحتاج مشاريع كثيرة إلى أي تخصيص للمحلل.
خيار css-loader | البديل الأصلي |
|---|---|
url | module.parser.css.url، وقيمته الافتراضية true |
import | module.parser.css.import، وقيمته الافتراضية true |
importLoaders | لا يوجد؛ تطبق loaders الموجودة في السلسلة تلقائيًا على الملفات المستوردة عبر @import |
sourceMap | يتحكم به devtool، ويدعم قيمة css خاصة بكل نوع |
esModule | module.generator.css.esModule، وقيمته الافتراضية true |
exportType: 'string' | خيار المحلل exportType: "text" |
exportType: 'css-style-sheet' | خيار المحلل exportType: "css-style-sheet" |
modules مع الاكتشاف التلقائي | نوع الوحدة المدمج css/auto |
modules.mode: 'local' | النوع css/module |
modules.mode: 'global' | النوع css/global |
modules.mode: 'pure' | خيار المحلل pure: true |
modules.localIdentName | خيار المولد localIdentName |
modules.exportLocalsConvention | خيار المولد exportsConvention |
modules.namedExport | خيار المحلل namedExports، وقيمته الافتراضية true |
modules.exportOnlyLocals | خيار المولد exportsOnly |
modules.localIdentHashSalt | خيار المولد localIdentHashSalt |
modules.localIdentHashFunction | خيار المولد localIdentHashFunction |
على سبيل المثال، إعداد CSS Modules التالي في css-loader:
export default {
module: {
rules: [
{
test: /\.module\.css$/i,
use: [
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[local]-[hash:base64:6]",
exportLocalsConvention: "camel-case-only",
namedExport: true,
},
},
},
],
},
],
},
};يصبح:
webpack.config.js
export default {
experiments: { css: true },
module: {
parser: {
"css/auto": {
namedExports: true,
},
},
generator: {
"css/auto": {
localIdentName: "[local]-[hash:base64:6]",
exportsConvention: "camel-case-only",
},
},
},
};تختلف بعض خيارات css-loader في طريقة نقلها:
getLocalIdent— يستخدم CSS الأصلي قالبlocalIdentNameلتوليد الأسماء بدل دالة مستقلة، ويمكن لهذا القالب نفسه أن يكون دالة.getJSON— تصدّر وحدة CSS خريطة أسماء الأصناف، ويمكن قراءتها من مخطط الوحدات في عملية التصريف. لذلك يستطيع ملحق صغير حفظها في JSON عندما يحتاج إطار العمل إلى ملف فعلي. وفي التصيير من جهة الخادم لا تحتاج إليها غالبًا؛ راجع التصيير من جهة الخادم.- لا يوجد بديل أصلي لـ
localIdentRegExpأو دوال التصفية الخاصة بـurlوimport. أبقِcss-loaderللملفات المتأثرة، أو استبعد طلبات معينة عبرIgnorePlugin.
5. استبدل style-loader
إذا كنت تستخدم style-loader لحقن الأنماط وقت التشغيل بدل استخراج ملف، فاضبط exportType: "style":
webpack.config.js
export default {
experiments: { css: true },
module: {
parser: {
"css/auto": {
exportType: "style",
},
},
},
};يحقن هذا الإعداد عنصر <style> من شيفرة runtime في webpack، ويغطي الاستخدام الافتراضي لـstyle-loader مع injectType: "styleTag". ويمكنك قصره على قاعدة واحدة إذا أردت حقن بعض الملفات مع استمرار استخراج البقية:
export default {
experiments: { css: true },
module: {
rules: [
{
test: /\.inline\.css$/i,
type: "css/auto",
parser: { exportType: "style" },
},
],
},
};ملاحظات حول خيارات style-loader: يقابل injectType: "linkTag" القيمة الافتراضية exportType: "link" التي تستخرج ملف CSS. ولا توجد بدائل أصلية للخيارات attributes وinsert وstyleTagTransform؛ أبقِ style-loader إذا كنت تعتمد عليها.
6. واصل استخدام المعالجات المسبقة (Sass وLess وPostCSS)
يستبدل CSS الأصلي loaders الخاصة بـCSS، لا loaders الخاصة بالمعالجات المسبقة. أبقِ loader المعالج ضمن use واضبط type في القاعدة على css/auto كي يتعامل webpack مع ناتج loader بوصفه CSS:
webpack.config.js
export default {
experiments: { css: true },
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: ["postcss-loader", "sass-loader"],
type: "css/auto",
},
],
},
};يحوّل sass-loader المصدر إلى CSS، ثم يعالجه postcss-loader، وبعد ذلك يتولى CSS الأصلي الاستخراج وurl() وCSS Modules. وينطبق النمط نفسه على less-loader وstylus-loader وما شابههما.
7. التصيير من جهة الخادم (node وweb)
في تطبيقات SSR، تُنشئ عادةً حزمتين: حزمة web للمتصفح وحزمة node للخادم. ويجب أن تتطابق أسماء أصناف CSS Modules حتى يُرطّب المتصفح الصفحة المصيّرة على الخادم من دون اختلافات. كان getJSON في css-loader يُستخدم غالبًا لمزامنة هذه الأسماء؛ أما مع CSS الأصلي، فيمكنك الاستغناء عن هذه الخطوة بجعل localIdentName حتميًا في الهدفين.
استخدم قالبًا يعتمد على المسار، من دون تجزئة شاملة لعملية التصريف، كي ينتج اسم الصنف نفسه في كل هدف:
webpack.config.js
const common = {
experiments: { css: true },
module: {
rules: [
{
test: /\.module\.css$/i,
type: "css/module",
generator: {
// يبقى `[file]__[local]` ثابتًا بين الأهداف، فلا حاجة إلى مزامنة getJSON.
localIdentName: "[file]__[local]",
},
},
],
},
};
export default [
{ ...common, name: "web", target: "web" },
{ ...common, name: "node", target: "node" },
];عند استخدام الهدف node، تكون القيمة الافتراضية لـexportsOnly في مولد CSS هي true. لذلك تصدّر حزمة الخادم خريطة أسماء الأصناف فقط، ولا تُخرج ورقة أنماط، وهو المطلوب في SSR. أما حزمة المتصفح فتواصل استخراج CSS الفعلي. وإذا كنت تفضل تخصيصًا واحدًا، فإن target: ["web", "node"] ينشئ حزمة عامة تعمل في البيئتين.
8. أبقِ الاستيرادات كما هي وتحقق من النتيجة
لا تتغير استيرادات JavaScript:
import "./styles.css";
import * as styles from "./button.module.css";ثم تحقق مما يلي:
- تُطبق الأنماط بصورة صحيحة في بيئة التطوير.
- تُخرج ملفات
.cssالمستخرجة في بناء الإنتاج. - تتطابق صادرات CSS Modules مع طريقة استخدام مشروعك لها.
جميع الخيارات مع أمثلة
اضبط الخيارات لكل نوع وحدة ضمن module.parser وmodule.generator. المفاتيح هي css وcss/auto وcss/global وcss/module. تستخدم الأمثلة التالية css/auto لأنه النوع المستخدم في القاعدة الافتراضية.
خيارات المحلل
القيمة الافتراضية لجميع خيارات المحلل المنطقية التالية هي true.
| الخيار | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
import | boolean | true | معالجة قواعد @import. |
url | boolean | true | معالجة url() وimage-set() وsrc() وimage(). |
namedExports | boolean | true | تصدير الأسماء المحلية في CSS Modules كصادرات مسماة لوحدة ES. |
exportType | "link" | "style" | "text" | "css-style-sheet" | "link" | كيفية إخراج CSS؛ راجع أوضاع الإخراج. |
pure | boolean | false | وضع نقي صارم؛ يجب أن يحتوي كل محدد على صنف أو معرّف محلي. خاص بـcss/module وcss/auto. |
as | "stylesheet" | "block-contents" | "stylesheet" | تحليل المصدر كورقة أنماط كاملة أو كمحتوى كتلة. |
animation | boolean | true | إعادة تسمية أسماء @keyframes المحلية. |
container | boolean | true | إعادة تسمية أسماء @container المحلية. |
customIdents | boolean | true | إعادة تسمية المعرّفات المخصصة. |
dashedIdents | boolean | true | إعادة تسمية المعرّفات ذات الشرطات، مثل الخصائص المخصصة. |
function | boolean | true | إعادة تسمية أسماء @function المحلية. |
grid | boolean | true | إعادة تسمية معرّفات خطوط الشبكة ومساحاتها. |
export default {
experiments: { css: true },
module: {
parser: {
"css/auto": {
import: true,
url: true,
namedExports: true,
exportType: "link",
pure: false,
// أعد تسمية @keyframes فقط، واترك معرّفات @container والشبكة كما هي.
animation: true,
container: false,
grid: false,
},
},
},
};خيارات المولد
| الخيار | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
localIdentName | string | function | "[uniqueName]-[id]-[local]" في التطوير و"[fullhash]" في الإنتاج | قالب أسماء الأصناف المحلية المولدة. |
exportsConvention | "as-is" | "camel-case" | "camel-case-only" | "dashes" | "dashes-only" | function | "as-is" | أسلوب تسمية الأسماء المحلية المصدّرة. |
exportsOnly | boolean | true في الأهداف التي لا تملك document مثل node، وإلا false | تصدير الأسماء المحلية فقط من دون إخراج ورقة أنماط. |
esModule | boolean | true | استخدام صياغة وحدات ES في JavaScript المولد. |
localIdentHashFunction | string | output.hashFunction | دالة التجزئة المستخدمة في localIdentName. |
localIdentHashDigest | string | "base64url" | ترميز تجزئة المعرّفات المحلية. |
localIdentHashDigestLength | number | 6 | طول تجزئة المعرّفات المحلية. |
localIdentHashSalt | string | output.hashSalt | الملح المستخدم في تجزئة المعرّفات المحلية. |
export default {
experiments: { css: true },
module: {
generator: {
"css/auto": {
localIdentName: "[uniqueName]-[id]-[local]",
exportsConvention: "camel-case-only",
esModule: true,
exportsOnly: false,
localIdentHashDigest: "base64url",
localIdentHashDigestLength: 6,
},
},
},
};يقبل exportsConvention أيضًا دالة تعيد string أو string[]. وعند إعادة مصفوفة، يُصدّر الاسم المحلي تحت عدة أسماء بديلة، كما يفعل css-loader.
أمثلة شائعة
CSS Modules مع صادرات مسماة
src/app.module.css
.primary {
color: #1f6feb;
}
.large-text {
font-size: 2rem;
}src/index.js
import { largeText, primary } from "./app.module.css";
document.body.classList.add(primary, largeText);webpack.config.js
export default {
experiments: { css: true },
module: {
generator: {
"css/auto": {
exportsConvention: "camel-case-only",
},
},
},
};استخراج ملفات CSS مجزأة للإنتاج
webpack.config.js
export default {
mode: "production",
experiments: { css: true },
output: {
cssFilename: "css/[name].[contenthash].css",
cssChunkFilename: "css/[id].[contenthash].css",
},
};حقن عناصر <style> وقت التشغيل كما يفعل style-loader
webpack.config.js
export default {
experiments: { css: true },
module: {
parser: {
"css/auto": {
exportType: "style",
},
},
},
};استيراد ورقة أنماط قابلة للإنشاء
src/index.js
import sheet from "./theme.css" with { type: "css" };
document.adoptedStyleSheets = [sheet];يحوّل webpack تأكيد الاستيراد with { type: "css" } تلقائيًا إلى exportType: "css-style-sheet"، ويمنحك نسخة من CSSStyleSheet.
استيراد CSS كسلسلة نصية
webpack.config.js
export default {
experiments: { css: true },
module: {
parser: {
"css/auto": {
exportType: "text",
},
},
},
};src/index.js
import css from "./styles.css";
const style = new CSSStyleSheet();
style.replaceSync(css);استخدام الأنماط العامة والوحدات محدودة النطاق معًا
مع قاعدة css/auto الافتراضية، تكون ملفات *.module.css محدودة النطاق، وتبقى بقية الملفات عامة، من دون تخصيص إضافي:
import "./reset.css"; // عام
import * as card from "./card.module.css"; // محدود النطاقالحالة التجريبية والقيود المعروفة
experiments.css ميزة تجريبية صراحةً؛ فعّلها باختيارك واختبرها بعناية قبل اعتمادها على نطاق واسع.
- قد تتغير واجهات API والسلوك قبل أن تصبح الميزة افتراضية في webpack v6.
- لا تملك بعض خيارات loaders بديلًا مباشرًا، ومنها
localIdentRegExpودوال التصفية فيcss-loader، والخياراتattributesوinsertوstyleTagTransformفيstyle-loader. أبقِ loader للملفات التي تحتاج إلى هذه الخيارات. يقابلgetLocalIdentصيغة الدالة فيlocalIdentName، ويغطي قسم مطابقة أسماء الأصناف بين الأهداف استخدامgetJSONوSSR. - لا يوجد بديل لـ
importLoaders، لأن loaders الموجودة في السلسلة تطبق تلقائيًا على الملفات المستوردة عبر@import. - إذا كان مشروعك يعتمد على سلاسل loaders متقدمة، فتحقق من كل جزء قبل الانتقال الكامل.



