Learning Parcel - Alternatif Webpack Untuk Proyek Kecil





Selamat siang teman!



Tujuan utama pembuat atau pemaket modul seperti Webpack atau Parcel adalah untuk memastikan bahwa semua modul yang diperlukan untuk menjalankan aplikasi disertakan dalam urutan yang benar dalam satu skrip yang diperkecil (untuk pembuatan produksi) yang disertakan dalam indeks. html.



Faktanya, pembangun, sebagai suatu peraturan, tidak hanya dapat mengoptimalkan JS, tetapi juga HTML, file CSS, dapat mengonversi Less, Sass ke CSS, TypeScript, React and Vue (JSX) ke JavaScript, bekerja dengan gambar, audio, video, dan lainnya. format data, dan juga menyediakan fitur tambahan, seperti: membuat peta (bekas) sumber daya atau sumber (peta sumber), representasi visual dari ukuran seluruh bundel dan bagian-bagian individualnya (modul, pustaka), membagi kode menjadi beberapa bagian (chunks), termasuk nomor, untuk tujuan penggunaan kembali (misalnya, pustaka yang digunakan dalam beberapa modul diambil dalam file terpisah dan dimuat hanya sekali), pemuatan paket yang cerdas dari npm (misalnya, memuat hanya lokalisasi Rusia dari moment.js), semua jenis plugin untuk menyelesaikan tugas-tugas tertentu dll.



Dalam hal ini, Webpack tidak diragukan lagi yang memimpin. Namun, bagaimana jika kita sedang mengembangkan proyek di mana sebagian besar fungsi yang disediakan oleh alat yang luar biasa ini tidak diperlukan? Adakah alternatif dari teknologi ini yang lebih mudah dipelajari dan digunakan? Bagi saya, jawaban untuk pertanyaan ini adalah Parcel . Ngomong-ngomong, jika Anda tertarik mempelajari Webpack, saya sarankan untuk menonton video ini . File saya dengan pengaturan Webpack untuk tutorial ini terletak di sini .



















Atas seizin Anda, saya tidak akan menceritakan kembali dokumentasi dengan kata-kata saya sendiri, terutama karena tersedia dalam bahasa Rusia, tetapi akan fokus pada komponen praktis, yaitu: menggunakan string template dan impor dinamis, kita akan membuat SPA yang terdiri dari tiga halaman dalam JavaScript, mengatur gaya aplikasi dengan CSS, menulis fungsi sederhana di TypeScript, mengimpornya ke dalam aplikasi, memberi gaya penampung untuk hasil fungsi ini menggunakan Sass, dan membangun aplikasi menggunakan Parcel dalam mode pengembangan dan produksi.



Kode proyek ada di sini .



Jika Anda tertarik, silakan ikuti saya.



aplikasi



Siap? Ayo pergi.



Buat direktori parcel-tutorial.



Kami masuk ke dalamnya dan menginisialisasi proyek menggunakan npm init -y.



Buat file index.html. Kami akan menggunakan salah satu template Bootstrap Cover standar:



<head>
    ...
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>

<!-- Bootstrap class -->
<body class="text-center">

    <! -- Main script -->
    <script src="index.js"></script>
</body>


Buka situs resmi Bootstrap , buka bagian Contoh, temukan Sampul di komponen Kustom, tekan Ctrl + U (Cmd + U) untuk melihat kode halaman.











Buat direktori src, dan ada dua folder lagi di dalamnya - js dan css.



Buat file berikut di direktori js: header.js, footer.js, home.js, projects.js dan contact.js. Ini adalah modul atau, jika Anda suka, komponen aplikasi kita: header, footer, konten halaman utama dan halaman lain.



Di direktori css, buat file style.css.



Saat ini, struktur proyek terlihat seperti ini:



-- parcel-tutorial
    -- src
        -- css
            -- style.css
        -- js
            -- contact.js
            -- footer.js
            -- header.js
            -- home.js
            -- projects.js
    -- index.html
    -- index.js
    -- package.json


Kembali ke Bootstrap.



Salin-tempel kode halaman ke modul yang sesuai dengan perubahan kecil.



header.js:



export default `
  <header class="masthead mb-auto">
      <div class="inner">
          <h3 class="masthead-brand">Parcel Tutorial</h3>
          <nav class="nav nav-masthead justify-content-center">
            <a class="nav-link active" name="home">Home</a>
            <a class="nav-link" name="projects">Projects</a>
            <a class="nav-link" name="contact">Contact</a>
        </nav>
      </div>
  </header>
`.trim()


Harap dicatat bahwa kami telah mengubah nama href menjadi di tautan.



footer.js:



export default `
  <footer class="mastfoot mt-auto">
    <div class="inner">
      <p>© 2020. All rights reserved.</p>
    </div>
  </footer>
`.trim()


home.js:



export default `
  <h1 class="cover-heading">Home page</h1>
  <p class="lead">Home page content</p>
`.trim()


projects.js:



export default `
  <h1 class="cover-heading">Projects page</h1>
  <p class="lead">Projects page content</p>
`.trim()


contact.js:



export default `
  <h1 class="cover-heading">Contact page</h1>
  <p class="lead">Contact page content</p>
`.trim()


Jangan lupa untuk menyalin style dari cover.css ke style.css.



Buka index.js.



Mari impor header, footer dan gaya:



import header from './src/js/header.js'
import footer from './src/js/footer.js'
import './src/css/style.css'


Konten halaman utama dan halaman lainnya akan dimuat secara dinamis saat tautan diklik, jadi kami membuat objek seperti itu:



const pages = {
    home: import('./src/js/home.js'),
    projects: import('./src/js/projects.js'),
    contact: import('./src/js/contact.js')
}


Nama properti objek ini adalah halaman yang sesuai (diminta oleh pengguna).



Kami membuat halaman awal menggunakan komponen header dan footer yang diimpor sebelumnya:



// Bootstrap classes
document.body.innerHTML = `
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
    ${header}
    <main role="main" class="inner cover"></main>
    ${footer}
</div>
`.trim()


Konten halaman akan ditampilkan di elemen utama, jadi kami mendefinisikannya:



const mainEl = document.querySelector('main')


Buat fungsi rendering halaman:



const renderPage = async name => {
    const template = await pages[name]
    mainEl.innerHTML = template.default
}


Kita perlu menunggu modul yang sesuai untuk dimuat, jadi kita menggunakan async / await (kata kunci await menjeda eksekusi fungsi). Fungsi tersebut mengambil nama dari halaman yang diminta (nama) dan menggunakannya untuk mengakses properti yang sesuai dari objek halaman (halaman [nama]). Kami kemudian memasukkan template yang dihasilkan ke mainEl. Faktanya, await menampilkan objek Module yang berisi template. Oleh karena itu, saat memasukkan template sebagai markup di mainEl, Anda perlu merujuk ke properti default dari objek Module (modul diekspor secara default), jika tidak, kami akan menerima pesan kesalahan - tidak mungkin mengubah objek ke HTML.



Render halaman utama:



renderPage('home')


Link aktif yang sesuai dengan halaman saat ini memiliki kelas aktif. Kita perlu mengganti kelas saat merender halaman baru. Mari terapkan fungsi helper:



const toggleClass = (activeLink, currentLink) => {
    if (activeLink === currentLink) {
        return;
    } else {
        activeLink.classList.remove('active')
        currentLink.classList.add('active')
    }
}


Fungsi tersebut mengambil dua argumen - tautan dengan kelas aktif (activeLink) dan tautan yang diklik (currentLink). Jika tautan yang ditentukan cocok, kami tidak melakukan apa-apa. Jika tidak, kami mengubah kelas.



Terakhir, kita perlu menambahkan handler klik tautan. Mari terapkan satu lagi fungsi pembantu:



const initClickHandlers = () => {
    const navEl = document.querySelector('nav')

    navEl.addEventListener('click', ev => {
        if (ev.target.tagName === 'A') {
            const activeLink = navEl.querySelector('.active')
            const currentLink = ev.target
            toggleClass(activeLink, currentLink)
            renderPage(currentLink.name)
        }
    })
}


Dalam fungsi ini, pertama-tama kita menemukan elemen nav. Kemudian, melalui pendelegasian, kami memproses klik tautan: jika elemen target adalah tag A, kami mendapatkan tautan aktif (tautan dengan kelas aktif), tautan saat ini (tautan yang diklik), mengubah kelas dan merender halaman. Nilai atribut name dari tautan saat ini diteruskan sebagai argumen renderPage.



Kami hampir selesai dengan aplikasinya. Namun, sebelum melanjutkan membangun proyek menggunakan Parcel, perlu diperhatikan hal-hal berikut: hari ini, dukungan untuk modul dinamis menurut data Dapatkah saya menggunakan 90%. Itu banyak, tapi kami belum siap kehilangan 10% pengguna kami. Oleh karena itu, kode kita perlu diubah menjadi sintaks yang kurang modern. Babel digunakan untuk transpilasi. Kami perlu menghubungkan dua modul tambahan:



import "core-js/stable";
import "regenerator-runtime/runtime";


Harap dicatat bahwa kami tidak menginstal paket-paket ini dengan npm.



Juga, mari kita segera mengimplementasikan fungsi dalam TypeScript, sesuatu yang sangat sederhana, seperti fungsi untuk menambahkan dua angka.



Buat file index.ts di direktori js dengan konten berikut:



export const sum = (a: number, b: number): number => a + b


Satu-satunya perbedaan dari JavaScript, selain ekstensi file (.ts), adalah kami secara eksplisit menentukan jenis nilai yang diterima dan dikembalikan oleh fungsi - dalam hal ini, angka. Faktanya, kita bisa membatasi diri kita sendiri untuk mendefinisikan tipe kembalian, TypeScript cukup pintar untuk mengetahui bahwa jika nilai kembalian adalah angka, maka argumen yang diteruskan haruslah angka. Sudahlah.



Mari impor fungsi ini ke index.js:



import { sum } from './src/js/index.ts'


Dan sebut dengan argumen 1 dan 2 di renderPage:



const renderPage = async name => {
    // ...
    mainEl.insertAdjacentHTML('beforeend', `
        <output>Result of 1 + 2 -> <span>${sum(1, 2)}<span></output>
    `)
}


Styling wadah hasil fungsi menggunakan Sass. Di folder css, buat file style.scss dengan konten berikut:



$color: #8e8e8e;

output {
    color: $color;
    border: 1px solid $color;
    border-radius: 4px;
    padding: .5rem;
    user-select: none;
    transition: transform .2s;

    & span {
        color: #eee;
    }

    &:hover {
        transform: scale(1.1);
    }
}


Mari impor gaya ini ke index.js:



import './src/css/style.scss'


Perhatikan lagi bahwa kami tidak menginstal TypeScript dan Sass dengan npm.



Kami selesai dengan aplikasinya. Pindah ke Parcel.



Paket



Untuk menginstal Parcel secara global, Anda perlu menjalankan perintah npm i parcel-bundler -gdi terminal.



Buka package.json dan siapkan peluncuran Parcel dalam mode pengembangan dan produksi:



"scripts": {
    "dev": "parcel index.html --no-source-maps --open",
    "pro": "parcel build index.html --no-source-maps --no-cache"
  },


Tim npm run devmulai membangun proyek untuk pengembangan, dan tim mulai npm run proproduksi. Tapi apa arti semua bendera ini? Dan mengapa kita tidak menginstal Babel, TypeScript dan Sass melalui npm?



Faktanya adalah bahwa Parcel secara otomatis menginstal semua dependensi ketika mendeteksi impor atau penggunaannya dalam aplikasi. Misalnya, jika Parcel melihat stylesheet diimpor dari file .scss, maka Sass akan diinstal.



Sekarang tentang tim dan bendera.



Untuk membangun proyek dalam mode pengembangan, gunakan perintah parcel index.html, di mana index.html adalah titik masuk aplikasi, mis. file yang berisi tautan ke skrip atau skrip utama. Selain itu, perintah ini memulai server lokal di localhost: 1234.



Bendera itu --no-source-mapsberarti kita tidak membutuhkan peta sumber daya.



Bendera--openmemberi tahu Parcel untuk membuka index.html setelah membangun browser di server lokal.



Untuk membangun proyek dalam mode produksi, gunakan perintah parcel build index.html. Rakitan ini mengasumsikan minifikasi file JS, CSS dan HTML.



Bendera --no-cacheberarti menonaktifkan cache sumber daya. Caching memberikan kecepatan tinggi untuk membangun dan membangun kembali proyek secara real time. Ini relevan saat mengembangkan, tetapi tidak terlalu banyak saat merakit produk jadi.



Satu hal lagi: Parcel menempatkan file yang dihasilkan di folder dist secara default, yang dibuat jika tidak ada. Masalahnya adalah ketika membangun kembali, file lama tidak terhapus. Untuk menghapus file semacam itu, Anda memerlukan plugin khusus, misalnya parcel-plugin-clean-easy .



Instal plugin ini menggunakannpm i parcel-plugin-clean-easy -D dan tambahkan yang berikut ini ke package.json:



"parcelCleanPaths": [
    "dist",
    ".cache"
  ]


parcelCleanPaths adalah direktori yang akan dihapus saat dibangun kembali.



Parcel sekarang sepenuhnya dikonfigurasi. Buka terminal, ketik npm run dev, tekan enter.















Parcel membangun proyek dalam mode pengembangan, memulai server lokal dan membuka aplikasi di browser. Luar biasa.



Sekarang mari kita coba menyusun proyek untuk produksi.



Kami menjalankan perintah npm run pro.











Kami meluncurkan aplikasi di browser.







Ups, sepertinya ada yang tidak beres.



Mari kita lihat index.html yang dihasilkan. Apa yang kita lihat disana? Petunjuk: Perhatikan jalur di tautan dan tag skrip. Saya tidak tahu persis apa kaitannya ini, tetapi Parcel mengonversi tautan relatif ke "/ path-to-file", dan browser tidak membaca tautan semacam itu.



Untuk mengatasi masalah ini, Anda perlu menambahkan bendera "--public-url." Ke skrip "pro".



Kami mulai membangun kembali.



Jalur relatif sudah benar dan aplikasi berfungsi. Keren.







Itu semua untukku. Terima kasih atas perhatian Anda.



All Articles