نحوه ساخت افزونه مرورگر با vue - بخش دوم

گردآوری و تالیف : عرفان کاکایی
تاریخ انتشار : 21 شهریور 1397
دسته بندی ها : جاوا اسکریپت

در بخش اول این مقاله در مورد قدم های ابتدای راه اندازی افزونه ها صحبت کردیم که میتوانید بخش اول را در نحوه ساخت افزونه مرورگر با vue - بخش اول مطالعه کنید 

در قسمت دوم این مقاله، نحوه کار با Vue بر روی افزونه‌ای که در قسمت اول ساختیم را به شما نشان خواهم داد.

پیش‌نیازها

$ npm -v
3.5.2
$ node -v
v8.10.0

اگر قسمت اول را خوانده باشید، حال باید یک پروژه افزونه داشته باشید که چنین ظاهری دارد:

 

هسته افزونه ما توسط یک فایل HTML به فایل app.html و اسکریپت موجود در فایل app.js ساخته شده است که مقداری عملکرد پایه به افزونه ما می‌دهد.

این یعنی این که ما می‌توانیم از تمام ابزاری که در هنگام توسعه یک وبسایت معمولی به استفاده از آن‌ها عادت داریم، استفاده کنیم.

اگر با Webpack یا Laravel Mix آشنایی ندارید، نگران نباشید؛ فقط این مراحل را دنبال کنید و وقتی که به استفاده از خود Vue برسیم، شما هم به با من همگام خواهید بود.

حال فایل package.json را راه‌اندازی کرده و Laravel Mix را وارد کنید:

npm init -y
npm i --save-dev laravel-mix

Laravel Mix یک فایل پیکربندی پیشفرض به همره دارد؛ پس بیایید آن را در شاخه ریشه خود کپی کنیم:

cp node_modules/laravel-mix/setup/webpack.mix.js .

حال افزونه ما چنین ظاهری خواهد داشت:

برخی اسکریپت‌ها وجود دارند که برای فایل package.json پیشنهاد می‌شوند و در راهنمای نصب Laravel Mix نیز وجود دارند. بیایید آن‌ها را نیز اضافه کنیم:

{
    ...
    "main": "app.js",
    "scripts": {
        "dev": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "hot": "NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "keywords": [],
    ...
}

حال بیایید کمی مرتب‌سازی سریع انجام دهیم و فایل app.js را به پوشه assets/js منتقل کنیم. ما باید مسیر فایل app.js در فایل app.html را نیز به درستی تنظیم کنیم، اما بعدا به آن بخش خواهیم رسید.

اگر فایل webpack.mix.js را باز کنید، خواهید دید که API کامل برای Laravel Mix را در خود دارد. شما تنها به یک فراخوانی متد نیاز خواهید داشت:

let mix = require('laravel-mix');
mix.js('assets/js/app.js', 'dist/');

حال اگر این دستور را اجرا کنید:

npm run dev

باید روند build خود را ببینید و پوشه dist باید در پوشه ریشه شما ظاهر شود:

نسخه dist از فایل app.js، فایلی است که در app.html لینک می‌کنیم.

نکته: dist مخفف distribution (توزیع) است. Laravel Mix خودش به خرد کردن کد JavaScript ما رسیدگی می‌کند، و همچنین تمام کارهای مورد نیاز دیگر را انجام می‌دهد. مثلا transpile کردن از ES6/7/8 به ES5، تا مرورگرهای قدیمی هم بتوانند کد را بخوانند.

حال بیایید این کار را انجام دهیم و همچنان که در آن فایل هستیم، کمی هم آن را مرتب کنیم.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div id="my-app"></div>
        <script src="dist/app.js"></script>
    </body>
</html>

همانطور که می‌توانید ببینید، من دکمه و لیستی که در بخش ۱ ساختیم را حذف کردم. حال تنها چیزی که نیاز داریم، یک wrapper است، تا نمونه Vue ما بتواند بر روی آن سوار شود. در این مورد، این wrapper همان div با آی‌دی my-app است. همچنین به مسیر فایل app.js که حال به درستی به نسخه ساخت شاخه dist اشاره می‌کند، دقت کنید.

بخش کار با Vue

در ابتدا، Vue را به عنوان یک Dependency وارد کنید:

npm i --save-dev vue

حال هر چیزی که برای شروع به ساخت نمونه Vue و سوار کردن مورد نیاز است را داریم. از آنجایی که app.js یک نقطه ورود به برنامه ما است، بیاید این کار را در آنجا انجام دهیم. می‌توانیم کد قبلی موجود در آن را به کلی حذف کنیم، زیرا در حال حاضر آنچنان مهم است.

حال فایل assets/js/app.js چنین ظاهری خواهد داشت:

import Vue from 'vue';
import App from './components/app.vue'

new Vue({
    el: '#my-app',
    components: {
        App
    },
    render(h) {
        return h('app');
    }
});

حال باید از تابع رندر Vue استفاده کنیم؛ زیرا Firefox به Vue اجازه نخواهد داد تا اسکریپت‌های رندر کردن را وارد کند. پس بیایید آن کامپوننت ریشه app.vue را بسازیم:

در فایل assets/js/components/app.vue:

<template>
    <div>
        Hello firefox extension. I am Vue!
    </div>
</template>
<script>
    export default { }
</script>

حال ساختار پروژه شما باید به این صورت باشد:

اجرای کد npm run dev را فراموش نکنید، تا تغییرات شما به JavaScript شما اعمال شوند. یا این که دستور npm run watch را اجرا کنید، تا assetهای شما هر زمان که شما تغییری اعمال می‌کنید، به صورت خودکار کمپایل شوند.

تا به اینجای پروژه را اجرا کنید، و نتیجه‌ای بسیار شبیه به اولین بخش این مقاله خواهید دید.

حال دومین افزونه Firefox خود را این بار با کمک Vue ساخته‌اید.

تقریبا کار به اتمام رسیده است

بخش قبلی می‌تواند آخرین بخش این مقاله باشد. زیرا اگر از قبل Vue را بلد باشید، دیگر می‌توانید هر کاری که می‌خواهید را انجام دهید.

اما من عملکرد مربوط به قسمت اول در Vue را به شما نشان خواهم داد. جهت یادآوری، ما در حال دسترسی به اطلاعات مرورگر درباره تب‌های باز در پنجره فعلی بودیم، و عنوان‌های آن‌ها را به یک لیست نامرتب اضافه می‌کردیم.

این کار آنچنان هم پیچیده نیست، پس بیایید آن را انجام دهیم.

حال اکثر کار ما در app.vue متمرکز خواهد بود، زیرا نیازی به تغییر app.js نیست.

در ابتدا بیایید HTML مورد نیاز را آماده کنیم:

<template>
    <div>
        <ul class="tab-list">
            <li class="tab-item">This is</li>
            <li class="tab-item">where the tabs</li>
            <li class="tab-item">will come</li>
        </ul>
        <button @click="getTabs()" class="button">Get tabs!</button>
    </div>
</template>
<script>
    ...
</script>
<style lang="scss">
    ...
</style>

این کد کافی خواهد بود، اما کمی استایل به آن اضافه خواهم کرد، تا ظاهر پیش‌فرض را نداشته باشد.

<template>
...
</template>
<script>
...
</script>
<style lang="scss">
    * { box-sizing: border-box; }
    body { min-width: 300px; font-family: sans-serif; padding: 1em; }

    .tab-list {
        list-style: none;
        margin: 0 0 1em 0;
        padding: 0;
    }

    .tab-item {
        padding: .6em;
        border-bottom: 1px dashed #eee;
    }

    button {
        border-radius: 2px;
        background: dodgerblue;
        color: white;
        font-weight: bold;
        text-align: center;
        padding: .6em .8em;
        border: 0;
        box-shadow: 0 1px 2px gray;
    }
</style>

پس حال، این صفحه چنین ظاهری خواهد داشت:

این عالی است، اما آیتم‌های موجود در لیست hardcode شده‌اند. بیایید با ساخت یک ویژگی داده با آرایه‌ای از تب‌های باز و لیست کردن آن‌ها در الگو، این مشکل را حل کنیم.

<template>
    <div>
        <ul class="tab-list">
            <li class="tab-item" v-for="tab in tabs">{{ tab }}</li>
        </ul>
        <button @click="getTabs()" class="button">Get tabs!</button>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                tabs: []
            }
        }
    }
</script>
<style lang="scss">
...
</style>

حال می‌توانیم متد getTabs را بسازیم، که تب‌ها را از مرورگر دریافت کرده، و نمایش خواهد داد:

<template>
...
</template>
<script>
    export default {
        data() {
            return {
                tabs: []
            }
        },
        methods: {
            async getTabs() {
                try {
                    // Await the tabs (since query method returns a promise)
                    const fetchedTabs = await browser.tabs.query({ currentWindow: true });
                    // Clear current tabs
                    this.tabs = [];
                    // Push new tabs
                    fetchedTabs.forEach(tab => {
                        this.tabs.push(tab.title);
                    })
                } catch (e) { console.log(e); }
            }
        }
    }
</script>
<style lang="scss">
...
</style>

متد getTabs تقریبا کاملا مشابه به بخش اول این مقاله است، اما این بار تصمیم گرفتم promiseای که متد query را بر می‌گرداند را با استفاده از روش async / await مدیریت کنم.

تقریبا در اینجا کار به پایان رسیده است و ما یک افزونه Firefox کاملا عملکردی داریم.

اما اگر می‌خواهید افزونه خود را با بقیه به اشتراک بگذارید چه؟ بیایید به این موضوع نیز نگاهی داشته باشیم.

چگونه افزونه Firefox خود را انتشار دهیم؟

در ابتدا باید یک آرشیو .zip از پروژه خود بسازید. شاخه node_modules را که شامل Dependencyهای مورد نیاز در طول توسعه را در خود دارد و بسیار حجیم است را در آن شامل نکنید. همچنین نیازی به شامل کردن پوشه assets/js ندارید، زیرا تمام اسکریپت‌های ضروری در شاخه dist کمپایل شده‌اند.

با استفاده از ترمینال، می‌توان با این صورت یک آرشیو zip ساخت:

zip -r my-extension.zip app.html assets/img dist manifest.json

این کد، یک آرشیو zip به نام my-extension.zip خواهد ساخت.

به صفحه «افزونه‌ها برای توسعه‌دهندگان» بر روی وبسایت mozilla.org‌ بروید و بر روی دکمه «Submit a New Add-on» کلیک کنید.

در اینجا می‌توانید انتخاب کنید که افزونه خود را با استفاده از Firefox Add-ons Manager توزیع کنید، یا به صورت دستی این کار را انجام دهید.

فعلا من با روش دستی پیش خواهم رفت. آرشیو خود را تایید کنید، و یک روند ثبت را مشاهده خواهید کرد.

بر روی دکمه «Sign Add-on» کلیک کنید، و سپس به قدم آخر منتقل خواهید شد که در آن یک فایل .xpi دانلود خواهید کرد، که نمایانگر افزونه شما خواهد بود.

حال به صفحه about:addons در Firefox بروید. بر روی چرخ دنده سمت راست کلیک کنید، و «Install Add-on from file»‌ را انتخاب کنید.

فایل .xpi را باز کنید، و به این صورت می‌توانید یک افزونه را نصب کنید.

منبع

مقالات پیشنهادی

نحوه ساخت افزونه مرورگر با vue - بخش اول

در این مقاله، نحوه ساخت یک افزونه ساده Firefox را با استفاده از فریم‌وورک معروف JavaScript، یعنی Vue نشان خواهم داد.

ایجاد اپلیکیشنی مدرن با استفاده از Django و Vue.js - بخش دوم

JWT یک URL-safe کوچک است که برای نمایش درستی یک انتقال بین دو موجودیت استفاده می‌شود. درستی در JWT در یک شئ اینکود شده داخل JSON قرار دارد و به عنوان...

ایجاد اپلیکیشنی مدرن با استفاده از Django و Vue.js - بخش اول

در این مقاله ما قصد داریم از چهارچوب Django و Django REST برای بک‌اند و Vue.js برای فرانت‌اند است. APIها با کمک Axois (یک کتابخانه HTTP Client) از طری...

ساخت یک برنامه چت Real-time با Sails.js | بخش دوم

در بخش قبل، تا مرحله تولید API کاربر پیش رفتیم. در این بخش نیز فرم پروفایل را ساخته، و باقی مراحل را پیش می رویم. ما در حال استفاده از Semantic-UI For...