Geliştirici İpuçları – Varlıklarınızı Verimli Bir Şekilde Derleme
Yayınlanan: 2022-08-25Bu yıl için sahip olduğumuz hedeflerden biri, iki amiral gemisi eklentimizi (Nelio Content ve Nelio A/B Testing) TypeScript ve React Hooks'a yeniden düzenlemekti. Pekala, henüz yarım yılı geride bıraktık ve şimdiden bu hedefin tam bir başarı olduğunu söyleyebiliriz. Ancak itiraf etmeliyim ki yol beklenenden biraz daha karmaşıktı… özellikle de TypeScript'i tanıttıktan sonra bunu düşünürsek, eklenti oluşturma süreleri birkaç saniyeden iki dakikanın üzerine çıktı! Bir şeyler yanlıştı ve ne olduğunu bilmiyorduk.
Pekala, bugünün gönderisinde size biraz bu deneyimden ve onu düzeltmek için ne yaptığımızdan bahsetmek istiyorum. Sonuçta, hepimiz TypeScript'in derleme sürecini her zaman biraz yavaşlatacağını biliyoruz (tür denetiminin bir bedeli vardır), ancak bu kadar olmamalı! Pekala, spoiler uyarısı: sorun asla TypeScript değildi… bu benim yapılandırmamdı. TypeScript bunu yalnızca "açık" hale getirdi. O halde başlayalım, olur mu?
Oyuncak Projesi
Birkaç hafta önce karşılaştığımız sorunu ve bunu nasıl düzelttiğimizi anlamanıza yardımcı olmak için yapabileceğimiz en iyi şey, izlemeniz için çok basit bir örnek oluşturmaktır. TypeScript kullanan basit bir WordPress eklentisi oluşturalım ve bir yanlış yapılandırmanın derleme sürelerinin son derece yavaş olmasına neden olabilir. Başlamak için yardıma ihtiyacınız varsa, WordPress geliştirme ortamlarıyla ilgili bu gönderiye göz atın.
Eklenti Oluşturma
Yapmanız gereken ilk şey, WordPress' /wp-content/plugins
dizininizde eklentinizin adıyla (örneğin, nelio
) yeni bir klasör oluşturmaktır. Ardından, aşağıdaki içeriğe sahip ana dosyayı ( nelio.php
) ekleyin:
<?php /** * Plugin Name: Nelio * Description: This is a test plugin. * Version: 0.0.1 * * Author: Nelio Software * Author URI: https://neliosoftware.com * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt * * Text Domain: nelio */ if ( ! defined( 'ABSPATH' ) ) { exit; }
Doğru yaptıysanız, eklentiyi artık WordPress'te etkinleştirebileceğinizi göreceksiniz:

Elbette, eklenti henüz hiçbir şey yapmıyor… ama en azından ortaya çıkıyor
TypeScript
Biraz TypeScript kodu ekleyelim! Yapacağımız ilk şey, eklenti klasörümüzde npm'yi başlatmak. Bunu çalıştırın:
npm init
ve ekrandaki talimatları izleyin. Ardından, bağımlılıkları yükleyin:
npm add -D @wordpress/scripts @wordpress/i18n
ve @wordpress/scripts
için gereken derleme komut dosyalarını eklemek için package.json
dosyasını düzenleyin:
{ ... "scripts": { "build": "wp-scripts build", "start": "wp-scripts start", }, ... }
npm hazır olduğunda, bir tsconfig.json
dosyası ekleyerek TypeScript'i özelleştirelim:
{ "compilerOptions": { "target": "es5", "module": "esnext", "moduleResolution": "node", "outDir": "build", "lib": [ "es7", "dom" ] }, "exclude": [ "node_modules" ] }
Son olarak, biraz TS kodu yazalım. Bunun çok basit ama Nelio A/B Testi ve Nelio İçeriğinde sahip olduğumuz şeye "yeterince yakın" olmasını istiyoruz, bu nedenle projemizde içinde birkaç TypeScript dosyası bulunan bir src
klasörü oluşturun: index.ts
ve utils/index.ts
.
Bir yandan, utils/index.ts
bir yardımcı program paketi olduğunu varsayalım. Yani projemizdeki diğer dosyaların ihtiyaç duyabileceği birkaç işlevi içerir. Örneğin, klasik min
ve max
işlevlerini sağladığını varsayalım:
export const min = ( a: number, b: number ): number => a < b ? a : b; export const max = ( a: number, b: number ): number => a > b ? a : b;
Öte yandan, uygulamamızın ana dosyasına bir göz atalım: index.ts
. Test amaçlarımız için tek istediğimiz, yardımcı program paketimizi ve bir WordPress bağımlılığını kullanan basit bir komut dosyası. Bunun gibi bir şey:
import { __, sprintf } from '@wordpress/i18n'; import { min } from './utils'; const a = 2; const b = 3; const m = min( a, b ); console.log( sprintf( /* translators: 1 -> num, 2 -> num, 3 -> num */ __( 'Min between %1$s and %2$s is %3$s', 'nelio' ), a, b, m ) );
@wordpress/scripts Varsayılan Ayarlar
Projeyi şu anda npm run build
kullanarak oluşturacak olsaydık, her şey kutudan çıktığı gibi çalışırdı. Bunun nedeni @wordpress/scripts
(yani projemizi oluşturmak için kullandığımız temel araç), örneğimizdeki gibi bir kod tabanı ile çalışmak üzere tasarlanmış olmasıdır. Yani, src
klasöründe bir index.ts
dosyamız varsa, build
klasöründe bir index.asset.php
bağımlılık dosyasıyla birlikte bir index.js
dosyası oluşturur:
> ls build index.asset.php index.js
Neden iki dosya? Pekala, biri derlenmiş JavaScript dosyası (hah), diğeri ise komut dosyamız hakkında bazı yararlı bilgiler içeren bir bağımlılıklar dosyası. Özellikle, bize WordPress'te bulunanlardan hangi JavaScript kitaplıklarına güvendiğini söyler. Örneğin, index.ts
, dizeleri uluslararası hale getirmek için @wordpress/i18n
paketine dayanır ve bu, WordPress'te bulunan bir kitaplıktır, yani… evet, wp-i18n
index.asset.php
dosyasında görünecektir:
build/index.asset.php <?php return array( 'dependencies' => array( 'wp-i18n' ), 'version' => 'c6131c7f24df4fa803b7', );
Ne yazık ki, bana sorarsanız, varsayılan yapılandırma mükemmel değil. İşte neden.
Kodunuza bir hata eklersek (örneğin, min
işlevini number
yerine arg string
çağıralım):
const m = min( `${ a }`, b );
bu bir hatayı tetiklemelidir. Ama öyle değil. Sorunsuz bir şekilde derleniyor.
TypeScript ile Derleme Sırasında Tip Kontrolleri
Yukarıda bahsedilen "sınırlamayı" çözmek için, kendi web paketi yapılandırma dosyamızı oluşturmamız ve TS koduyla karşılaştığında tsc
(TypeScript derleyicisi) kullanmasını söylememiz yeterlidir. Başka bir deyişle, aşağıdaki webpack.config.json
dosyasına ihtiyacımız var:
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' ); const config = { ...defaultConfig, module: { ...defaultConfig.module, rules: [ ...defaultConfig.module.rules, { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, }; module.exports = { ...config, entry: './src/index', output: { path: __dirname + '/build', filename: 'index.js', }, };
Gördüğünüz gibi, @wordpress/scripts
paketinde bulunan varsayılan web paketi yapılandırmasını yükleyerek başlar ve ardından tüm .ts
dosyalarına bir ts-loader
ekleyerek defaultConfig
genişletir. Basit!
Ve şimdi, bakın:
> npm run build ... ERROR in ...src/index.ts TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. webpack 5.74.0 compiled with 1 error in 4470 ms
projemizi derlemek bir hatayla sonuçlanır. Yaşasın! Elbette biraz daha yavaş ama en azından üretime herhangi bir şey yüklemeden önce bazı güvenlik kontrollerimiz var.
Komut Dosyalarını Sıraya Alma
Artık kodunuzda bir sorun olduğunu bildiğinize göre, düzeltin ve eklentiyi yeniden derleyin. Hepsi işe yaradı mı? Serin! Çünkü şimdi tarayıcımızda deneyebilmemiz için betiği ve PHP'deki bağımlılıklarını sıraya koymanın zamanı geldi.
nelio.php
açın ve aşağıdaki parçacığı ekleyin:
add_action( 'admin_enqueue_scripts', function() { $path = untrailingslashit( plugin_dir_path( __FILE__ ) ); $url = untrailingslashit( plugin_dir_url( __FILE__ ) ); $asset = require( $path . '/build/index.asset.php' ); wp_enqueue_script( 'nelio', $url . '/build/index.js', $asset['dependencies'], $asset['version'] ); } );
Ardından, WordPress panosuna gidin (herhangi bir sayfa hile yapacaktır) ve tarayıcınızın JavaScript konsoluna bir göz atın. Aşağıdaki metni görmelisiniz:
Min between 2 and 3 is 2
Güzel!
Bağımlılıklarım ne olacak?
JavaScript/webpack/WordPress'te bağımlılık yönetimi hakkında biraz konuşalım. @wordpress/scripts
, varsayılan olarak, projeniz WordPress çekirdeğinde paketlenmiş bir bağımlılık kullanıyorsa, .asset.php
dosyasında bu şekilde listelenecek şekilde yapılandırılır. Bu, örneğin, komut dosyamızın bağımlılıklar dosyasında @wordpress/i18n
neden listelendiğini açıklar.
Peki ya “diğer” paketlere bağımlılıklar? utils
paketimize ne oldu? Uzun lafın kısası: varsayılan olarak web paketi tüm bağımlılıkları derler ve çıktı komut dosyasına birleştirir Sadece oluşturulan JS dosyasına bakın (minification'ı devre dışı bırakmak için npm run start
ile derleyin):
... var __webpack_modules__ = ({ "./src/utils/index.ts": ((...) => ... var min = function (a, b) { return a < b ? a : b; }; var max = function (a, b) { return a > b ? a : b; }; }), ...
Görmek? utils
kodumuz tam orada, çıktı komut dosyamıza gömülü.

@wordpress/i18n
ne olacak? Peki, bu sadece global bir değişkene basit bir referans:
... var __webpack_modules__ = ({ "./src/utils/index.ts": ..., "@wordpress/i18n": ((module)) => { module.exports = window["wp"]["i18n"]; }) ...
Dediğim gibi, @wordpress/scripts
, belirli bağımlılıkları derleme işleminden "hariç tutan" ve bunların global kapsamda kullanılabileceğini varsayarak kod üreten bir eklenti olan Dependency Extraction Webpack Plugin ile birlikte gelir. Örneğimizde @wordpress/i18n
wp.i18n
içinde olduğunu görebiliriz. Bu yüzden betiğimizi kuyruğa alırken, onun bağımlılıklarını da kuyruğa almamız gerekiyor.
İki Ayrı Komut Dosyası Oluşturmak için Özel Yapılandırma
Tüm bunları göz önünde bulundurarak, utils
paketimizle aynı şeyi başarmak istediğimizi varsayalım. Yani, içeriğinin index.js
içine gömülmesini istemiyoruz, bunun yerine kendi .js
dosyasında derlenmeli ve index.asset.php
bir bağımlılık olarak görünmelidir. Bunu nasıl yaparız?
İlk olarak, index.js
import
ifadesini gerçek bir paket gibi görünecek şekilde yeniden adlandırmalıyız. Başka bir deyişle, betiği göreceli bir yol ( ./utils
) kullanarak içe aktarmak yerine, @nelio/utils
gibi bir ad kullanabilseydik iyi olurdu. Bunu yapmak için tek yapmanız gereken, dependencies
yeni bir bağımlılık eklemek için projenin package.json
dosyasını düzenlemek:
{ ... "dependencies": { "@nelio/utils": "./src/utils" }, "devDependencies": { "@wordpress/i18n": ..., "@wordpress/scripts": ... }, ... }
node_modules
içinde bu "yeni" paketi işaret eden bir sembolik bağlantı oluşturmak için npm install
çalıştırın ve son olarak npm init
src/utils
içinde çalıştırın, böylece npm'nin bakış açısından @nelio/utils
geçerli bir paket olur.
Ardından, @nelio/utils
kendi betiğinde derlemek için webpack.config.js
yapılandırmamızı düzenlememiz ve iki dışa aktarma tanımlamamız gerekiyor:
- zaten sahip olduğumuz (
./src/index.ts
) -
./src/utils
dosyasını farklı bir dosyaya derlemek için başka bir dışa aktarma, dışa aktarmalarını örneğinnelio.utils
adlı global bir değişkende gösterir.
Başka bir deyişle, şunu istiyoruz:
module.exports = [ { ...config, entry: './src/index', output: { path: __dirname + '/build', filename: 'index.js', }, }, { ...config, entry: './src/utils', output: { path: __dirname + '/build', filename: 'utils.js', library: [ 'nelio', 'utils' ], libraryTarget: 'window', }, }, ];
Kodu tekrar derleyin ve ./build
klasörüne bir göz atın - artık hepimizin iki betiği olduğunu göreceksiniz. ./build/utils.js
bir göz atın ve beklendiği gibi nelio.utils
nasıl tanımladığını göreceksiniz:
... var min = function (a, b) { return a < b ? a : b; }; var max = function (a, b) { return a > b ? a : b; }; (window.nelio = window.nelio || {}).utils = __webpack_exports__; ...
... var min = function (a, b) { return a < b ? a : b; }; var max = function (a, b) { return a > b ? a : b; }; (window.nelio = window.nelio || {}).utils = __webpack_exports__; ...
Ne yazık ki, daha yolun yarısındayız. ./build/index.js dosyasına da bir göz atarsanız, src/utils
./build/index.js
hala içinde gömülü olduğunu göreceksiniz… bunun bir “dış bağımlılık” olması ve az önce tanımladığımız global değişkeni kullanması gerekmez mi?
Dış Bağımlılıklar Oluşturmak için Özel Yapılandırma
@nelio/utils
gerçek bir harici bağımlılığa dönüştürmek için web paketimizi daha fazla özelleştirmemiz ve daha önce bahsettiğimiz bağımlılık çıkarma eklentisinden yararlanmamız gerekiyor. webpack.config.js
dosyasını yeniden açın ve config
değişkenini aşağıdaki gibi değiştirin:
const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extraction-webpack-plugin' ); const config = { ...defaultConfig, module: { ...defaultConfig.module, rules: [ ...defaultConfig.module.rules, { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, plugins: [ ...defaultConfig.plugins.filter( ( p ) => p.constructor.name !== 'DependencyExtractionWebpackPlugin' ), new DependencyExtractionWebpackPlugin( { requestToExternal: ( request ) => '@nelio/utils' === request ? [ 'nelio', 'utils' ] : undefined, requestToHandle: ( request ) => '@nelio/utils' === request ? 'nelio-utils' : undefined, outputFormat: 'php', } ), ], };
böylece @nelio/utils
yapılan tüm başvurular kodda nelio.utils
olarak çevrilir ve nelio-utils
komut dosyası işleyicisine bir bağımlılık vardır. Her iki betiğin bağımlılıklarına bir göz atarsak, aşağıdakileri görürüz:
build/index.asset.php <?php return array( 'dependencies' => array('nelio-utils', 'wp-i18n')... ?> build/utils.asset.php <?php return array( 'dependencies' => array()... ?>
ve ./build/index.js
bakarsak, gerçekten de @nelio/utils
bağımlılığının artık harici olduğunu onaylarız:
... var __webpack_modules__ = ({ "@nelio/utils": ((module)) => { module.exports = window["nelio"]["utils"]; }), "@wordpress/i18n": ((module)) => { module.exports = window["wp"]["i18n"]; }) ...
Yine de ele almamız gereken son bir sorun var. Tarayıcınıza gidin, gösterge tablosu sayfasını yenileyin ve konsola bakın. Hiçbir şey görünmüyor, değil mi? Neden? Niye? nelio
artık nelio-utils
bağlı, ancak bu komut dosyaları WordPress'te kayıtlı değil… bu nedenle bağımlılıkları şu anda karşılanamıyor. Bunu düzeltmek için nelio.php
dosyasını düzenleyin ve yeni komut dosyasını kaydedin:
add_action( 'admin_enqueue_scripts', function() { $path = untrailingslashit( plugin_dir_path( __FILE__ ) ); $url = untrailingslashit( plugin_dir_url( __FILE__ ) ); $asset = require( $path . '/build/utils.asset.php' ); wp_register_script( 'nelio-utils', $url . '/build/utils.js', $asset['dependencies'], $asset['version'] ); } );
İnşa Süreci Nasıl Hızlandırılır
Derleme işlemini birkaç kez çalıştırırsak ve ortalama ne kadar sürede tamamlanırsa, derlemenin yaklaşık 10 saniye içinde çalıştığını görürüz:
> yarn run build ... ./src/index.ts + 2 modules ... webpack 5.74.0 compiled successfully in 5703 ms ... ./src/utils/index.ts ... webpack 5.74.0 compiled successfully in 5726 m Done in 10.22s.
bu çok fazla görünmeyebilir ama bu basit bir oyuncak projesi ve dediğim gibi, Nelio Content veya Nelio A/B Testing gibi gerçek projelerin derlenmesi dakikalar alıyor.
Neden “çok yavaş” ve hızlandırmak için ne yapabiliriz? Söyleyebileceğim kadarıyla, sorun web paketi yapılandırmamızda yatıyordu. wepack'inizin module.exports
dosyasında ne kadar çok dışa aktarmaya sahip olursanız, derleme süresi o kadar yavaş olur. Ancak, tek bir dışa aktarma çok daha hızlıdır.
Tek bir dışa aktarma kullanmak için projemizi biraz yeniden düzenleyelim. Her şeyden önce, src/utils
içinde aşağıdaki içeriğe sahip bir export.ts
dosyası oluşturun:
export * as utils from './index';
Ardından, webpack.config.js
iki girişli tek bir dışa aktarmaya sahip olacak şekilde düzenleyin:
module.exports = { ...config, entry: { index: './src/index', utils: './src/utils/export', }, output: { path: __dirname + '/dist', filename: 'js/[name].js', library: { name: 'nelio', type: 'assign-properties', }, }, };
Son olarak, projeyi tekrar oluşturun:
> yarn run build ... built modules 522 bytes [built] ./src/index.ts + 2 modules ... ./src/utils/export.ts + 1 modules ... webpack 5.74.0 compiled successfully in 4339 ms Done in 6.02s.
Sadece 6 saniye sürdü, bu da eskisinin neredeyse yarısı kadardı! Oldukça temiz, ha?
Özet
TypeScript , kodun kalitesini artırmanıza yardımcı olur, çünkü derleme zamanında türlerin doğru olup olmadığını ve tutarsızlık olmadığını kontrol etmenizi sağlar. Ancak hayattaki her şeyde olduğu gibi TypeScript kullanmanın avantajlarının da bir bedeli vardır: kodu derlemek biraz daha yavaş olur.
Bugünkü gönderide, web paketinizin yapılandırmasına bağlı olarak projenizi derlemenin çok daha hızlı (veya daha yavaş) olabileceğini gördük. Tatlı nokta tek bir ihracat gerektiriyor… ve bugün bahsettiğimiz şey bu.
Umarım gönderiyi beğenmişsinizdir. Eğer öyleyse, lütfen paylaşın. Web paketini optimize etmenin başka yollarını biliyorsanız, lütfen aşağıdaki yorum bölümünde bana bildirin. İyi günler!
Unsplash'ta Saffu'nun öne çıkan görseli.