SQLite Wasm في المتصفّح المتوافق مع Origin Private File System

يمكنك استخدام SQLite للتعامل مع جميع احتياجات التخزين لديك بشكل فعّال على الويب.

لمحة عن SQLite

SQLite هو نظام شائع ومفتوح المصدر وخفيف لإدارة قواعد البيانات الارتباطية مضمّن. يستخدمه العديد من المطورين لتخزين البيانات بطريقة منظمة وسهلة الاستخدام. نظرًا لحجمها الصغير وانخفاض متطلبات الذاكرة، غالبًا ما تتم الاستفادة من SQLite كمحرك قاعدة بيانات في الأجهزة المحمولة وتطبيقات سطح المكتب ومتصفحات الويب.

تتمثل إحدى الميزات الرئيسية لتطبيق SQLite في أنها قاعدة بيانات بدون خادم، مما يعني أنها لا تتطلب عملية خادم منفصلة للتشغيل. فبدلاً من ذلك، يتم تخزين قاعدة البيانات في ملف واحد على جهاز المستخدم، ما يسهِّل عملية الدمج في التطبيقات.

شعار SQLite

SQLite على أساس Web Assembly

هناك عدد من إصدارات SQLite غير الرسمية التي تستند إلى Web Assembly (Wasm)، والتي تسمح باستخدامها في متصفحات الويب، على سبيل المثال، sql.js. يُعد المشروع الفرعي sqlite3 WASM/JS الجهد الأول المرتبط رسميًا بمشروع SQLite الذي ينشئ إصدارات Wasm للمكتبة من أفراد عائلة عائلة من المُخرَجات النهائية المدعومة في SQLite. تشمل الأهداف الملموسة لهذا المشروع ما يلي:

  • ربط واجهة برمجة تطبيقات sqlite3 منخفضة المستوى تكون قريبة من واجهة C قدر الإمكان من حيث الاستخدام.
  • واجهة برمجة تطبيقات ذات مستوى أعلى موجهة نحو الكائن، تشبه إلى حدٍ كبير عمليات التنفيذ بنمط sql.js ونمط Node.js، تتحدث مباشرةً عن واجهة برمجة التطبيقات منخفضة المستوى. يجب استخدام واجهة برمجة التطبيقات هذه من نفس سلسلة التعليمات مثل واجهة برمجة التطبيقات ذات المستوى المنخفض.
  • واجهة برمجة تطبيقات تستند إلى عامل التشغيل وتتحدث عن واجهات برمجة التطبيقات السابقة من خلال رسائل العاملين. هذه الواجهة مخصّصة للاستخدام في سلسلة التعليمات الرئيسية مع تثبيت واجهات برمجة التطبيقات ذات المستوى الأدنى في سلسلة محادثات Worker والتحدّث إلى الفريق عبر رسائل Worker.
  • يشير ذلك المصطلح إلى إصدار قائمة على وعد من واجهة برمجة تطبيقات Worker API، وهو تطبيق يخفي تمامًا جوانب التواصل بين سلاسل المحادثات من المستخدمين.
  • توفير مساحة تخزين دائمة من جهة العميل باستخدام واجهات برمجة تطبيقات JavaScript المتاحة، بما في ذلك نظام الملفات الخاصة المصدر (OPFS).

استخدام SQLite Wasm مع الواجهة الخلفية لاستمرارية نظام الملفات الخاصة لـ Origin

تثبيت المكتبة من npm

ثبِّت حزمة @sqlite.org/sqlite-wasm من npm باستخدام الأمر التالي:

npm install @sqlite.org/sqlite-wasm

نظام الملفات الخاصة وأصلي

يتم تعزيز نظام الملفات الخاصة (OPFS، وهو جزء من واجهة برمجة تطبيقات الوصول إلى نظام الملفات) مع مساحة خاصة تتيح الوصول بشكل فعّال إلى البيانات. تختلف هذه الواجهة الجديدة عن مساحات العرض الحالية من خلال توفير إذن وصول حصري وحصري إلى محتوى الملف. إنّ هذا التغيير، بالإضافة إلى إمكانية قراءة التعديلات غير النشطة وتوفُّر متغيّر متزامن على العاملين المكرسين، يعمل على تحسين الأداء بشكل كبير وإزالة حظر حالات الاستخدام الجديدة.

كما يمكنك أن تتخيل، فإن النقطة الأخيرة من أهداف المشروع، وهي دعم التخزين الدائم من جهة العميل باستخدام واجهات برمجة تطبيقات JavaScript المتاحة، يأتي مع متطلبات أداء صارمة بشأن البيانات المستمرة في ملف قاعدة البيانات. وهنا يأتي دور نظام الملفات الخاصة لأصول البيانات، وبشكل أكثر تحديدًا، طريقة createSyncAccessHandle() لكائنات FileSystemFileHandle. تعرض هذه الطريقة Promise وتحلّ محلّها كائن FileSystemSyncAccessHandle الذي يمكن استخدامه للقراءة من ملف والكتابة إليه بشكل متزامن. توفّر الطبيعة المتزامنة لهذه الطريقة مزايا في الأداء، ومن ثمَّ لا يمكن استخدامها إلا داخل عاملي الويب المخصّصين للملفات داخل نظام الملفات الخاصة المصدر، وبالتالي لا يمكن حظر سلسلة التعليمات الرئيسية.

إعداد العناوين المطلوبة

من بين الملفات الأخرى، يحتوي أرشيف SQLite Wasm الذي تم تنزيله على ملفَي sqlite3.js وsqlite3.wasm اللذين يتكوّنان من إصدار WASM/JS sqlite3. يحتوي دليل jswasm على المُخرَجات النهائية الأساسية لـ sqlite3، ويحتوي دليل المستوى الأعلى على تطبيقات توضيحية واختبار. لن تعرض المتصفّحات ملفات Wasm من عناوين URL لـ file://، لذلك تتطلّب أي تطبيقات تُنشئها باستخدام هذا خادم ويب ويجب أن يتضمّن هذا الخادم العناوين التالية في استجابته عند عرض الملفات:

  • تم ضبط Cross-Origin-Opener-Policy على التوجيه same-origin، الذي يعزل سياق التصفّح حصريًا على المستندات من المصدر نفسه. لا يتم تحميل المستندات المشتركة المصادر في سياق التصفُّح نفسه.
  • تم ضبط Cross-Origin-Embedder-Policy على التوجيه require-corp، وبذلك يمكن للمستند تحميل الموارد من المصدر نفسه فقط، أو الموارد التي تم وضع علامة عليها بوضوح كقابلة للتحميل من مصدر آخر.

يرجع السبب في هذه العناوين إلى أنّ SQLite Wasm يعتمد على SharedArrayBuffer، ويشكّل ضبط هذه العناوين جزءًا من متطلبات الأمان لديها.

إذا فحصت عدد الزيارات باستخدام "أدوات مطوري البرامج"، ستظهر لك المعلومات التالية:

العنوانان المذكوران أعلاه، وهما Cross-Origin-embedder-Policy و Cross-Origin-Opener-Policy، اللذين تم تمييزهما في "أدوات مطوري البرامج في Chrome".

اختبار السرعة

نفذ فريق SQLite بعض المعايير على تنفيذ WebAssembly مقارنة بـ Web SQL المتوقّف. تُظهر مقاييس الأداء هذه أن SQLite Wasm يعمل بشكل عام بنفس سرعة Web SQL. أحيانًا تكون أبطأ قليلاً، وأحيانًا تكون أسرع قليلاً. يمكنك الاطّلاع على جميع التفاصيل في صفحة النتائج.

نموذج رمز البدء

كما ذكرنا سابقًا، يجب تشغيل SQLite Wasm باستخدام الواجهة الخلفية لاستمرار نظام الملفات الخاصة من سياق Worker. والخبر السار هو أن المكتبة تعتني تلقائيًا بكل هذا من أجلك ويمكنك استخدامها مباشرةً من سلسلة التعليمات الرئيسية.

import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';

(async () => {
  try {
    console.log('Loading and initializing SQLite3 module...');

    const promiser = await new Promise((resolve) => {
      const _promiser = sqlite3Worker1Promiser({
        onready: () => {
          resolve(_promiser);
        },
      });
    });

    console.log('Done initializing. Running demo...');

    let response;

    response = await promiser('config-get', {});
    console.log('Running SQLite3 version', response.result.version.libVersion);

    response = await promiser('open', {
      filename: 'file:worker-promiser.sqlite3?vfs=opfs',
    });
    const { dbId } = response;
    console.log(
      'OPFS is available, created persisted database at',
      response.result.filename.replace(/^file:(.*?)\?vfs=opfs$/, '$1'),
    );

    await promiser('exec', { dbId, sql: 'CREATE TABLE IF NOT EXISTS t(a,b)' });
    console.log('Creating a table...');

    console.log('Insert some data using exec()...');
    for (let i = 20; i <= 25; ++i) {
      await promiser('exec', {
        dbId,
        sql: 'INSERT INTO t(a,b) VALUES (?,?)',
        bind: [i, i * 2],
      });
    }

    console.log('Query data with exec()');
    await promiser('exec', {
      dbId,
      sql: 'SELECT a FROM t ORDER BY a LIMIT 3',
      callback: (result) => {
        if (!result.row) {
          return;
        }
        console.log(result.row);
      },
    });

    await promiser('close', { dbId });
  } catch (err) {
    if (!(err instanceof Error)) {
      err = new Error(err.result.message);
    }
    console.error(err.name, err.message);
  }
})();

الخصائص الديموغرافية

يمكنك الاطّلاع على الرمز أعلاه في العرض التوضيحي. اطّلِع على رمز المصدر على Glitch. يُرجى العلم أنّ الإصدار المضمّن أدناه لا يستخدم الواجهة الخلفية لـ OPFS، لكن عند فتح العرض التوضيحي في علامة تبويب منفصلة، يتم استخدامه.

تصحيح أخطاء نظام الملفات الخاصة المصدر

لتصحيح أخطاء مخرجات نظام الملفات الخاصة لـ SQLite Wasm، استخدِم الإضافة OPFS Explorer على Chrome.

مستكشف OPFS في سوق Chrome الإلكتروني.

بعد تثبيت الإضافة، افتح "أدوات مطوري البرامج في Chrome"، واختَر علامة التبويب مستكشف OPFS، وستكون جاهزًا لفحص ما يكتبه SQLite Wasm في نظام الملفات الخاصة لأصول البيانات.

إضافة OPFS Explorer في متصفّح Chrome تعرض بنية نظام الملفات الخاصة لمصدر التطبيق التجريبي.

إذا نقرت على أي من الملفات في نافذة "مستكشف OPFS" ضمن "أدوات مطوري البرامج"، يمكنك حفظه على القرص المحلي. يمكنك بعد ذلك استخدام تطبيق مثل SQLite Viewer لفحص قاعدة البيانات، بحيث يمكنك أن تطمئن نفسك بأن SQLite Wasm يعمل بالفعل على النحو الموعود.

تطبيق SQLite Viewer المستخدم لفتح ملف قاعدة بيانات من الإصدار التجريبي لـ SQLite Wasm.

الحصول على المساعدة وتقديم الملاحظات

تم تطوير SQLite Wasm وصيانته من قبل مجتمع SQLite. احصل على مساعدة وقدم ملاحظاتك من خلال البحث في منتدى الدعم ونشر مشاركات فيه. تتوفر الوثائق الكاملة على موقع SQLite.

شكر وتقدير

صورة رئيسية من تصوير توبياس فيشر على قناة UnLaunch