معالج SASS/SCSS

SASS مع أدوات البناء: npm Scripts و Webpack

20 دقيقة الدرس 26 من 30

مقدمة إلى أدوات بناء SASS

يتطلب تطوير الويب الحديث أدوات بناء لترجمة SASS، وتحسين الموارد، وأتمتة سير عمل التطوير. في هذا الدرس الشامل، سنستكشف أدوات البناء المختلفة وكيفية دمج SASS في خط أنابيب التطوير الخاص بك، من سكريبتات npm البسيطة إلى أدوات التجميع المتقدمة مثل Webpack و Vite.

إعداد سكريبتات npm لترجمة SASS

توفر سكريبتات npm طريقة بسيطة وخالية من التبعيات لترجمة ملفات SASS. يتم تعريفها في ملف package.json ويمكن تنفيذها باستخدام npm run.

تثبيت SASS

أولاً، قم بتثبيت SASS كاعتمادية تطوير:

تثبيت الحزمة

# تثبيت Dart Sass (موصى به)
npm install --save-dev sass

# أو تثبيت node-sass (قديم، غير موصى به)
npm install --save-dev node-sass
ملاحظة: Dart Sass هو التطبيق الأساسي ويتم صيانته بنشاط. node-sass قديم ويجب تجنبه في المشاريع الجديدة.

تكوين سكريبتات npm الأساسية

أضف سكريبتات الترجمة إلى ملف package.json:

package.json - السكريبتات الأساسية

{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build:css": "sass src/scss/main.scss dist/css/main.css",
    "watch:css": "sass --watch src/scss:dist/css",
    "build:css:compressed": "sass src/scss/main.scss dist/css/main.min.css --style=compressed"
  },
  "devDependencies": {
    "sass": "^1.69.0"
  }
}

سكريبتات npm المتقدمة

أنشئ سكريبتات أكثر تطوراً مع خرائط المصدر ومعالجة الأخطاء والتنفيذ المتوازي:

package.json - السكريبتات المتقدمة

{
  "scripts": {
    "sass:dev": "sass src/scss:dist/css --source-map --watch",
    "sass:build": "sass src/scss:dist/css --no-source-map --style=compressed",
    "sass:lint": "stylelint \"src/scss/**/*.scss\" --fix",
    "prebuild": "npm run sass:lint",
    "build": "npm run sass:build",
    "dev": "npm-run-all --parallel sass:dev serve",
    "serve": "lite-server"
  },
  "devDependencies": {
    "sass": "^1.69.0",
    "npm-run-all": "^4.1.5",
    "lite-server": "^2.6.1",
    "stylelint": "^15.10.3",
    "stylelint-config-standard-scss": "^11.0.0"
  }
}

دمج PostCSS مع SASS

PostCSS هو أداة لتحويل CSS باستخدام إضافات JavaScript. يعمل بشكل مثالي مع SASS لإضافة بادئات البائعين وتصغير الإخراج وتطبيق تحويلات أخرى.

تثبيت PostCSS

تثبيت PostCSS

npm install --save-dev postcss postcss-cli autoprefixer cssnano

تكوين PostCSS

أنشئ ملف postcss.config.js:

postcss.config.js

module.exports = {
  plugins: [
    require('autoprefixer')({
      overrideBrowserslist: ['last 2 versions', '> 1%', 'IE 11']
    }),
    require('cssnano')({
      preset: ['default', {
        discardComments: {
          removeAll: true
        },
        normalizeWhitespace: false
      }]
    })
  ]
};

خط أنابيب SASS و PostCSS المدمج

package.json - SASS + PostCSS

{
  "scripts": {
    "sass:compile": "sass src/scss:dist/css --no-source-map",
    "postcss:process": "postcss dist/css/*.css --dir dist/css --replace",
    "build:css": "npm run sass:compile && npm run postcss:process",
    "watch:sass": "sass --watch src/scss:dist/css",
    "watch:postcss": "postcss dist/css/*.css --dir dist/css --watch",
    "dev": "npm-run-all --parallel watch:sass watch:postcss"
  }
}

تكوين Webpack مع SASS

Webpack هو أداة تجميع وحدات قوية يمكنها التعامل مع ترجمة SASS جنباً إلى جنب مع تجميع JavaScript وتحسين الصور والمزيد.

تثبيت Webpack ومحمّلات SASS

اعتماديات Webpack

npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev sass-loader sass css-loader style-loader
npm install --save-dev mini-css-extract-plugin css-minimizer-webpack-plugin

تكوين Webpack الأساسي

webpack.config.js - الإعداد الأساسي

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles.css'
    })
  ]
};

تكوين Webpack المتقدم

webpack.config.js - إعداد الإنتاج

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    mode: isProduction ? 'production' : 'development',
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle.[contenthash].js',
      clean: true
    },
    devtool: isProduction ? 'source-map' : 'eval-source-map',
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                sourceMap: true,
                importLoaders: 2
              }
            },
            {
              loader: 'postcss-loader',
              options: {
                sourceMap: true,
                postcssOptions: {
                  plugins: [
                    ['autoprefixer'],
                    ['cssnano', { preset: 'default' }]
                  ]
                }
              }
            },
            {
              loader: 'sass-loader',
              options: {
                sourceMap: true,
                sassOptions: {
                  outputStyle: isProduction ? 'compressed' : 'expanded',
                  includePaths: [path.resolve(__dirname, 'src/scss')]
                }
              }
            }
          ]
        },
        {
          test: /\.(png|svg|jpg|jpeg|gif)$/i,
          type: 'asset/resource'
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/i,
          type: 'asset/resource'
        }
      ]
    },
    plugins: [
      new MiniCssExtractPlugin({
        filename: isProduction ? 'styles.[contenthash].css' : 'styles.css'
      })
    ],
    optimization: {
      minimizer: [
        `...`,
        new CssMinimizerPlugin()
      ]
    },
    devServer: {
      static: './dist',
      hot: true,
      port: 3000
    }
  };
};

استخدام SASS في نقطة دخول Webpack

src/index.js - استيراد SASS

// استورد ملف SASS الرئيسي
import './scss/main.scss';

// كود JavaScript الخاص بك
console.log('تم تهيئة التطبيق');

دمج Vite و SASS

Vite هي أداة بناء حديثة مع دعم SASS الأصلي. تتطلب الحد الأدنى من التكوين وتوفر استبدال وحدة ساخن (HMR) سريع بشكل لا يصدق.

تثبيت Vite

تثبيت Vite

npm install --save-dev vite sass

تكوين Vite

يعمل Vite مع SASS مباشرة، لكن يمكنك تخصيصه:

vite.config.js

import { defineConfig } from 'vite';
import path from 'path';

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "sass:math"; @import "@/styles/variables";`,
        includePaths: [path.resolve(__dirname, 'src/scss')]
      }
    },
    devSourcemap: true
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },
  build: {
    sourcemap: true,
    cssCodeSplit: true,
    rollupOptions: {
      output: {
        assetFileNames: 'assets/[name].[hash][extname]'
      }
    }
  }
});

سكريبتات npm لـ Vite

package.json - سكريبتات Vite

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

Gulp مع SASS

Gulp هو منفذ مهام يمكنه تنظيم سير عمل بناء معقد. على الرغم من أنه أقل شعبية من Webpack أو Vite، إلا أنه لا يزال يُستخدم في العديد من المشاريع.

تثبيت Gulp و SASS

تثبيت Gulp

npm install --save-dev gulp gulp-sass sass gulp-postcss autoprefixer cssnano gulp-sourcemaps

تكوين Gulpfile

gulpfile.js

const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const sourcemaps = require('gulp-sourcemaps');

// المسارات
const paths = {
  scss: {
    src: 'src/scss/**/*.scss',
    dest: 'dist/css'
  }
};

// مهمة ترجمة SASS
function compileSass() {
  return gulp.src(paths.scss.src)
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'expanded' }).on('error', sass.logError))
    .pipe(postcss([autoprefixer(), cssnano()]))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(paths.scss.dest));
}

// مهمة المراقبة
function watchFiles() {
  gulp.watch(paths.scss.src, compileSass);
}

// تصدير المهام
exports.sass = compileSass;
exports.watch = watchFiles;
exports.default = gulp.series(compileSass, watchFiles);

خرائط المصدر: التطوير مقابل الإنتاج

تساعدك خرائط المصدر في تصحيح CSS المترجم عن طريق ربطه بملفات SASS الأصلية. ومع ذلك، يجب التعامل معها بشكل مختلف في التطوير والإنتاج.

خرائط مصدر التطوير

// خرائط مصدر كاملة للتصحيح
sass src/scss:dist/css --source-map --embed-sources

// تطوير Webpack
devtool: 'eval-source-map'

// تطوير Vite
css: {
  devSourcemap: true
}

خرائط مصدر الإنتاج

// خرائط مصدر خارجية (لا تدمج المصادر)
sass src/scss:dist/css --source-map

// أو تعطيل تماماً لحجم ملف أصغر
sass src/scss:dist/css --no-source-map

// إنتاج Webpack
devtool: 'source-map' // أو false للتعطيل

// إنتاج Vite
build: {
  sourcemap: true // أو false
}
نصيحة: في الإنتاج، يمكنك تحميل خرائط المصدر إلى خدمات تتبع الأخطاء (مثل Sentry) دون تقديمها للمستخدمين، مما يوفر إمكانيات التصحيح دون الكشف عن التعليمات البرمجية المصدر.

التصغير والتحسين

يمكن للتصغير المناسب تقليل أحجام ملفات CSS بنسبة 40-60٪، مما يحسن أوقات التحميل بشكل كبير.

ضغط SASS المدمج

أنماط إخراج SASS

# موسع (قابل للقراءة، للتطوير)
sass src/scss:dist/css --style=expanded

# مضغوط (مصغر، للإنتاج)
sass src/scss:dist/css --style=compressed

التحسين المتقدم باستخدام cssnano

تكوين cssnano

// postcss.config.js
module.exports = {
  plugins: [
    require('cssnano')({
      preset: ['advanced', {
        discardComments: { removeAll: true },
        reduceIdents: false, // الحفاظ على أسماء @keyframes
        zindex: false, // لا تعدل قيم z-index
        mergeRules: true,
        cssDeclarationSorter: true
      }]
    })
  ]
};

استبدال الوحدة الساخن (HMR)

يحدّث HMR الأنماط الخاصة بك في المتصفح دون إعادة تحميل الصفحة بالكامل، مع الحفاظ على حالة التطبيق أثناء التطوير.

خادم تطوير Webpack مع HMR

webpack.config.js - إعداد HMR

module.exports = {
  devServer: {
    static: './dist',
    hot: true, // تفعيل HMR
    liveReload: true,
    watchFiles: ['src/**/*.scss'],
    port: 3000,
    open: true
  }
};

Vite HMR

يحتوي Vite على HMR مفعّل افتراضياً مع تحديثات سريعة بشكل لا يصدق:

Vite HMR (تلقائي)

// فقط قم بتشغيل خادم التطوير
npm run dev

// يكتشف Vite تلقائياً تغييرات SASS ويحدث على الفور
ملاحظة: HMR الخاص بـ Vite أسرع بكثير من Webpack لأنه يستخدم وحدات ES الأصلية ولا يحتاج إلى التجميع أثناء التطوير.

مثال على إعداد بناء كامل

إليك package.json كامل مع جميع السكريبتات لمشروع احترافي:

package.json - الإعداد الكامل

{
  "name": "sass-project",
  "version": "1.0.0",
  "scripts": {
    "clean": "rimraf dist",
    "sass:dev": "sass src/scss:dist/css --source-map --watch",
    "sass:build": "sass src/scss:dist/css --no-source-map --style=compressed",
    "postcss:dev": "postcss dist/css/*.css --dir dist/css --watch",
    "postcss:build": "postcss dist/css/*.css --dir dist/css --replace",
    "lint:scss": "stylelint \"src/scss/**/*.scss\" --fix",
    "dev": "npm-run-all clean --parallel sass:dev serve",
    "build": "npm-run-all clean lint:scss sass:build postcss:build",
    "serve": "browser-sync start --server dist --files \"dist/**/*\"",
    "webpack:dev": "webpack serve --mode=development",
    "webpack:build": "webpack --mode=production",
    "vite:dev": "vite",
    "vite:build": "vite build",
    "vite:preview": "vite preview"
  },
  "devDependencies": {
    "sass": "^1.69.0",
    "postcss": "^8.4.31",
    "postcss-cli": "^10.1.0",
    "autoprefixer": "^10.4.16",
    "cssnano": "^6.0.1",
    "stylelint": "^15.10.3",
    "stylelint-config-standard-scss": "^11.0.0",
    "npm-run-all": "^4.1.5",
    "rimraf": "^5.0.5",
    "browser-sync": "^2.29.3",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1",
    "sass-loader": "^13.3.2",
    "css-loader": "^6.8.1",
    "mini-css-extract-plugin": "^2.7.6",
    "css-minimizer-webpack-plugin": "^5.0.1",
    "vite": "^5.0.0"
  }
}

تمرين 1: إعداد سكريبتات npm الأساسية

أنشئ مشروعاً جديداً مع سكريبتات npm لترجمة SASS:

  1. قم بتهيئة مشروع npm جديد: npm init -y
  2. ثبّت SASS: npm install --save-dev sass
  3. أنشئ ملف src/scss/main.scss مع بعض الأنماط
  4. أضف سكريبتات إلى package.json للبناء ومراقبة SASS
  5. اختبر السكريبتات: npm run build:css و npm run watch:css

تمرين 2: دمج PostCSS

أضف PostCSS إلى خط أنابيب SASS الخاص بك:

  1. ثبّت PostCSS و autoprefixer و cssnano
  2. أنشئ ملف postcss.config.js
  3. حدّث سكريبتات npm لتشغيل PostCSS بعد ترجمة SASS
  4. أضف خاصية CSS تحتاج إلى بادئة (مثل user-select: none;) وتحقق من أن autoprefixer يضيف بادئات البائعين
  5. قارن أحجام الملفات قبل وبعد تحسين cssnano

تمرين 3: تكوين Webpack أو Vite

أعد نظام بناء كامل باستخدام Webpack أو Vite:

  1. اختر إما Webpack أو Vite وثبّت الاعتماديات المطلوبة
  2. أنشئ ملف التكوين (webpack.config.js أو vite.config.js)
  3. كوّن تحميل SASS مع خرائط المصدر
  4. أعد أوضاع التطوير والإنتاج
  5. اختبر استبدال الوحدة الساخن بتشغيل خادم التطوير وتحرير ملفات SASS
  6. بناء للإنتاج والتحقق من أن الإخراج مصغر ومحسّن