Cara Mudah Memindahkan Addon Ember Ke Format v2
Menuju edisi Polaris, satu perubahan besar sudah dipublikasikan di dunia Ember JS: Embroider, sistem build generasi selanjutnya yang mempunyai tujuan untuk mempererat kesenjangan di antara Ember dan ekosistem JS yang bertambah luas, menghasilkan banyak manfaat setelah diadopsi. Sama seperti yang disebutkan dalam RFC-nya:
add-on yang kurang "khusus", yang hanya akan menjadi package NPM biasa | |
build yang lebih cepat dan pemasangan NPM. | |
dapat memanfaatkan alat build yang ada seperti Webpack atau Vite | |
membawa fitur-fitur penting yang sudah lama tidak dimiliki oleh ekosistem Ember seperti tree shaking dan pemecahan kode |
Tetapi hari ini, saya hanya akan fokus pada point pertama kali yang tercatat: membuat addon Ember Classic lebih sedikit "Embery" dengan memigrasikannya ke Format Addon v2 baru, yang bisa saja meskipun Embroider belum jadi sistem standar. Sejauh sisa posting ini, saya akan melalui beberapa langkah berbeda yang dibutuhkan dan permasalahan yang saya hadapi di sepanjang pekerjaan dan bagaimana saya melakukan perbaikan.
Konteks
Addon yang saya kerjakan mencakup fitur-fitur berikut ini:
Naskah | |
Jasa | |
Adaptor Data Ember, model, serializer | |
Komponen (campuran Glimmer dan Ember Classic) | |
Terjemahan (didukung oleh ember-intl) | |
Beberapa aset publik (gambar) yang digunakan dalam komponen perlu disalin ke aplikasi induk | |
Beberapa CSS (diproses sebelumnya menggunakan Less) |
Di sisi perkakas, saya memakai Yarn (sayangnya saat ini masih di v1).
NI ialah pertama kalinya saya harus bekerja dengan monorepos (Ruang Kerja Benang di sini) hingga beberapa permasalahan yang saya temui mungkin berkaitan dengan minimnya pengetahuan saya mengenainya.
Menjalankan codemod
Bila belum selesai, saya sangat merekomendasikan Anda membaca tutorial migrasi untuk mem-porting addons v1 ke format v2 karena memberi banyak penjelasan mengenai pohon file baru.
Untungnya, semenjak pola v2 dikenalkan, beberapa codemods sudah dicatat oleh komunitas untuk mempercepat prosesnya dan saya menggunakan ember-codemod-v1-to-v2 (ember-addon-migrator sebagai opsi tapi saya melakukannya belum mengetesnya).
npx [email protected] --addon-location="packages/addon" --test-app-location="packages/test-app"
Pada titik ini, codemod dapat menyiapkan ruang kerja Yarn dengan:
package addon: ini adalah kode add-on Anda yang sebenarnya yang Anda harapkan disediakan untuk aplikasi induk | |
package aplikasi uji, membawa peran yang sama dengan aplikasi dummy dalam format v1. |
Itu juga menambahkan beberapa skrip ke dalam setiap package untuk:
membangun addon (termasuk dalam mode jam tangan) | |
jalankan server aplikasi pengujian | |
jalankan pengujian di aplikasi pengujian |
Ini berarti jika Anda mempunyai beberapa CI yang menjalankan perintah ini (untuk pengetesan atau linting misalnya), Anda perlu memastikan bahwa perintah itu dijalankan dalam package yang betul. Di Github, ini gampang dilakukan dengan tentukan kunci directory kerja.
Berurusan dengan terjemahan
Menggunakan ember-intl, ada directory terjemahan di root project yang ditinggalkan oleh codemod, yang mengakibatkan hilangnya terjemahan bila dibutuhkan. Untuk melakukan perbaikan, saya perlu memindahkan directory terjemahan ke root package addon, lalu mencantumkannya di kolom `files` di packages/my-addon/package.json
sehingga dipublikasi dan ada untuk program induk.
{
"name": "my-addon",
"version": "0.0.13",
"keywords": [
"ember-addon"
],
...,
"files": [
"addon-main.cjs",
"dist",
"translations"
]
}
Membangun konfigurasi waktu
Karena addon dikirimkan dengan adaptor Ember Data, itu perlu dikonfigurasi untuk mencapai host backend yang pas tergantung pada lingkungan program induk yang berjalan.
Sebelumnya, kita akan melakukan seperti ini:
import { getOwner } from '@ember/application';
export default class BaseAdapter extends AuthorizedAdapter {
get namespace(): string {
return 'api/v1';
}
get host(): string {
const config = getOwner(this).resolveRegistration('config:environment')['my-addon'];
return config.backendURL;
}
}
Selanjutnya kita akan menambahkan backendURL berbasis variabel lingkungan ke file addon (v1) config/environment.js
.
Sayangnya, ini tidak berfungsi lagi karena format v2 ialah tentang lebih sedikit keajaiban dan lebih sedikit keajaiban waktu pembuatan. Tetapi tetap dapat memakai @embroider/macros.
Dengan memakai package ini, saya bisa mengonfigurasikan host yang pas hanya dengan mengupdate nilai object konfigurasi:
import { getOwnConfig } from '@embroider/macros';
export default class BaseAdapter extends AuthorizedAdapter {
get namespace(): string {
return 'api/v1';
}
get host(): string {
return (getOwnConfig() || {}).backendURL;
}
}
Di aplikasi induk, ini dikonfigurasi di file ember-cli-build.js
dan terlihat seperti:
module.exports = function (defaults) {
let app = new EmberAddon(defaults, {
'@embroider/macros': {
setConfig: {
'my-addon': {
backendURL: process.env.BACKEND_URL || 'https://some-default.api.io'
}
}
}
});
}
Dan inilah! Kita perlu memberi masukan variabel environment BACKEND_URL dengan benar tergantung pada apa kita sedang dalam produksi atau pementasan sekarang ini.
Menyediakan asset publik
Sesudah menautkan addon di program yang benar-benar menggunakannya, saya perhatikan jika semua gambar yang umumnya disertakan dengannya tidak berada di build program.
Rupanya, file-file di folder publik addon (yang perlu dipindah kepackages/my-addon/public
, btw) harus terdaftar di object meta addon package.json
's ember-addon.public-assets
di format berikut ini:
{
"name": "my-addon",
"version": "0.0.13",
"keywords": [
"ember-addon"
],
"ember-addon": {
...,
"public-assets": {
"./public/assets/images/tomster.png": "/my-addon/assets/images/tomster.png",
"./public/assets/images/zoey.svg": "/my-addon/assets/images/zoey.svg"
}
}
...
}
Di titik ini, asset publik siap dipublikasi dengan addon dan disalin dengan benar di build program induk.
Tetapi, walau ini bisa sangat cepat untuk addon yang hanya sediakan beberapa asset publik, itu dapat terlepas kendali bila jumlahnya banyak, jadi ada keinginan tarik terbuka untuk menambahkan plugin Rollup bawaan yang menjaga object meta ember-addon.public-assets sinkron dengan directory publik.
Menangani CSS
Sama seperti yang dinyatakan sebelumnya, addon ini menyediakan beberapa komponen dan CSS-nya, diproses sebelumnya memakai Less CSS. Saya pun tidak mempunyai komponen yang mengimpor CSS mereka sendiri sebelumnya, tetapi addon/styles/addon.less
file entrypoint yang mengimpor file relatif lainnya. Untuk menghindar melalui semua komponen dan menempatkan CSS mereka di sampingnya, saya memilih untuk meneruskan dengan satu file CSS untuk sekarang ini . Maka saya mempunyai dua permasalahan untuk ditangani pada saat ini:
CSS yang tidak diimpor dari file JS akan dihilangkan
ember-cli-less
tidak berfungsi lagi untuk menangani lebih sedikit file
Dengan bantuan dari komunitas (terima kasih @nullvoxpopuli), rupanya file CSS keluaran perlu dicantumkan di package's exports addon:
{
"name": "my-addon",
"version": "0.0.13",
"keywords": [
"ember-addon"
],
...,
"exports": {
".": "./dist/index.js",
"./*": {
"types": "./dist/*.d.ts",
"default": "./dist/*.js"
},
"./addon-main.js": "./addon-main.cjs",
"./styles": "./dist/styles/_addon.css",
},
}
Kemudian dapat diimpor dalam file JS. Saya memilih app/app.js
aplikasi induk untuk saat ini:
import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
import 'my-addon/styles';
export default class App extends Application {
modulePrefix = config.modulePrefix;
Resolver = Resolver;
}
loadInitializers(App, config.modulePrefix);
Bila Anda mempunyai lebih banyak waktu untuk melakukan investasi di sini atau hanya beberapa komponen, saya sarankan untuk pilih rute colocation karena itu pantas untuk setidaknya dua argumen:
dalam hal refactoring: Anda memiliki segalanya di samping satu sama lain | |
itu membuat tree-shaking lebih mudah dan Anda tidak akan mengirim CSS mati ke browser |
Adapun permasalahan preprocessing, saya berusaha untuk menemukan jalan keluar yang ada untuk file LESS ke CSS seperti ember-cli-less, jadi saya menulis plugin Rollup inline kecil memakai package less tersebut. Itu menyebabkan sesuatu seperti :
import { readFileSync, writeFileSync } from 'fs';
import less from 'less';
import { Addon } from '@embroider/addon-dev/rollup';
const addon = new Addon({
srcDir: 'src',
destDir: 'dist'
});
export default {
// This provides defaults that work well alongside `publicEntrypoints` below.
// You can augment this if you need to.
output: addon.output(),
plugins: [
// Made sure to do the preprocessing before the keepAssets plugin is ran.
{
name: 'less-handler',
generateBundle() {
const lessCode = readFileSync('src/styles/main.less', 'utf-8');
less.render(
lessCode,
{
paths: ['src/styles']
},
(err, rendered) => {
if (err) {
console.log(err);
return;
}
const css = rendered.css;
const filename = path.join('src', 'styles', '_addon.css');
mkdirp.sync(path.dirname(filename));
writeFileSync(filename, css);
}
);
}
},
// addons are allowed to contain imports of .css files, which we want rollup
// to leave alone and keep in the published output.
addon.keepAssets(['**/*.css']),
// Remaining plugins from the sample file
]
};
Tentu saja, jalan keluar ini jauh dari sempurna tapi membuat saya bekerja dengan versi file yang kurang diproses sebelumnya.
Penyelesaian masalah
Ini ialah beberapa permasalahan yang mudah diperbaiki sesudah menjalankan codemod:
bidang deklarasi pertama-tama harus diubah oleh @babel/plugin-transform-typescript. Diperbaiki dengan mengaktifkan opsi allowDeclareFields . |
|
Saat mengganti impor lama (dengan nama package sebagai root) dengan impor relatif, codemod secara tidak sengaja mengganti jalur aset yang dibangun secara dinamis di beberapa komponen dengan impor relatif, merusak beberapa jalur gambar. Pemeriksaan ganda cepat mungkin diperlukan di sini. | |
css-loader ember-auto-import gagal menangani url dengan jalur relatif. Ini adalah masalah umum dengan Webpack yang saya alami bahkan di luar konteks migrasi ini. Untuk saat ini, memulai autoImport.cssLoaderOptions.url ke false |