Modern JavaScript bağımlılıkları ve çıkışını etkinleştirerek performansı iyileştirin.
Tarayıcıların% 90'ından fazlası modern JavaScript'i çalıştırabilir ancak eski JavaScript'in yaygınlığı günümüzde web'de performans sorunlarının önemli bir kaynağı olmaya devam etmektedir.
Modern JavaScript
Modern JavaScript, belirli bir ECMAScript spesifikasyon sürümünde yazılmış kod olarak değil, tüm modern tarayıcılar tarafından desteklenen söz dizimi olarak tanımlanır. Chrome, Edge, Firefox ve Safari gibi modern web tarayıcıları tarayıcı pazarının% 90'ından fazlasını oluştururken aynı temel oluşturma motorlarını kullanan farklı tarayıcılar da ek %5'i oluşturur. Bu, dünya genelindeki web trafiğinin% 95'inin aşağıdakiler dahil olmak üzere son 10 yılda en yaygın kullanılan JavaScript dil özelliklerini destekleyen tarayıcılardan geldiği anlamına gelir:
- Sınıflar (ES2015)
- Ok işlevleri (ES2015)
- Jeneratörler (ES2015)
- Blok kapsamı (ES2015)
- Yapıyı bozma (ES2015)
- Rest ve spread parametreleri (ES2015)
- Nesne kısaltması (ES2015)
- Eş zamansız/bekle (ES2017)
Dil spesifikasyonunun yeni sürümlerindeki özellikler, modern tarayıcılarda genellikle daha tutarlı bir şekilde desteklenmez. Örneğin, birçok ES2020 ve ES2021 özelliği yalnızca tarayıcı pazarının% 70'inde desteklenir. Bu, tarayıcı sayısının çoğunu ifade etse de bu özelliklere doğrudan güvenmenin güvenli olduğu anlamına gelmez. Bu, "modern" JavaScript değişen bir hedef olsa da ES2017'nin yaygın olarak kullanılan modern söz dizimi özelliklerinin çoğunu içermesine rağmen en geniş tarayıcı uyumluluğu yelpazesine sahip olduğu anlamına gelir. Diğer bir deyişle, ES2017 günümüzün modern söz dizimine en yakın sürümdür.
Eski JavaScript
Eski JavaScript, özellikle yukarıdaki tüm dil özelliklerinin kullanılmadığı koddur. Çoğu geliştirici, kaynak kodlarını modern söz dizimi kullanarak yazar ancak daha fazla tarayıcı desteği için her şeyi eski söz dizimine derleyebilir. Eski söz dizimi için derleme yapmak tarayıcı desteğini artırır ancak bu etki genellikle düşündüğümüzden daha küçüktür. Birçok durumda, destek yaklaşık %95'ten% 98'e çıkarken önemli bir maliyete neden olur:
Eski JavaScript, genellikle eşdeğer modern koda kıyasla yaklaşık% 20 daha büyük ve daha yavaştır. Araç eksiklikleri ve yanlış yapılandırmalar genellikle bu farkı daha da artırır.
Yüklenen kitaplıklar, tipik üretim JavaScript kodunun% 90'ını oluşturur. Kitaplık kodu, modern kod yayınlanarak önlenebilen çoklu doldurma ve yardımcı programın kopyalanması nedeniyle eski JavaScript'in daha da yüksek bir yükü oluşturur.
npm'de modern JavaScript
Node.js, kısa süre önce bir paketin giriş noktalarını tanımlamak için "exports"
alanını standartlaştırdı:
{
"exports": "./index.js"
}
"exports"
alanının referans verdiği modüller, ES2019'u destekleyen en az 12.8 sürümüne sahip bir Node sürümünü ifade eder. Bu, "exports"
alanı kullanılarak referans verilen tüm modüllerin modern JavaScript ile yazılabileceği anlamına gelir. Paket kullanıcıları, "exports"
alanı içeren modüllerin modern kod içerdiğini varsaymalı ve gerekirse derlemeyi yeniden yapmalıdır.
Yalnızca modern
Modern kod içeren bir paket yayınlamak ve paketi bağımlılık olarak kullanırken derlemeyi kullanıcıya bırakmak istiyorsanız yalnızca "exports"
alanını kullanın.
{
"name": "foo",
"exports": "./modern.js"
}
Eski yedek ile modern
Paketinizi modern kod kullanarak yayınlamak ancak eski tarayıcılar için ES5 + CommonJS yedek seçeneği de eklemek istiyorsanız "main"
ile birlikte "exports"
alanını kullanın.
{
"name": "foo",
"exports": "./modern.js",
"main": "./legacy.cjs"
}
Eski yedek ve ESM paketleyici optimizasyonlarıyla modern
"module"
alanı, yedek bir CommonJS giriş noktası tanımlamanın yanı sıra, JavaScript modülü söz dizimini (import
ve export
) kullanan benzer bir eski yedek paketi işaretlemek için de kullanılabilir.
{
"name": "foo",
"exports": "./modern.js",
"main": "./legacy.cjs",
"module": "./module.js"
}
Webpack ve Rollup gibi birçok paketleyici, modül özelliklerinden yararlanmak ve ağaç sallamayı etkinleştirmek için bu alandan yararlanır.
Bu, import
/export
söz diziminden başka modern kod içermeyen eski bir pakettir. Bu nedenle, modern kodu, hâlâ paket oluşturma için optimize edilmiş eski bir yedek ile birlikte göndermek için bu yaklaşımı kullanın.
Uygulamalarda modern JavaScript
Üçüncü taraf bağımlılıkları, web uygulamalarındaki tipik üretim JavaScript kodunun büyük çoğunluğunu oluşturur. npm bağımlılıkları geçmişte eski ES5 söz dizimi olarak yayınlanmış olsa da bu artık güvenli bir varsayım değildir ve bağımlılık güncellemelerinin uygulamanızdaki tarayıcı desteğini bozma riski vardır.
Modern JavaScript'e geçiş yapan npm paketlerinin sayısı arttıkça derleme araçlarının bunları işleyebilecek şekilde ayarlandığından emin olmanız önemlidir. Bağımlı olduğunuz npm paketlerinden bazılarının modern dil özelliklerini zaten kullanıyor olması muhtemeldir. Uygulamanızı eski tarayıcılarda bozmadan npm'den modern kod kullanmak için çeşitli seçenekler vardır. Ancak genel fikir, derleme sisteminin bağımlılıkları kaynak kodunuzla aynı söz dizimi hedefine derlemesi şeklindedir.
webpack
webpack 5'ten itibaren, webpack'ın paketler ve modüller için kod oluştururken kullanacağı söz dizimi yapılandırılabilir. Bu işlem, kodunuzu veya bağımlılıklarınızı derlemez. Yalnızca webpack tarafından oluşturulan "yapıştırıcı" kodunu etkiler. Tarayıcı desteği hedefini belirtmek için projenize bir browserslist yapılandırması ekleyin veya bunu doğrudan webpack yapılandırmanızda yapın:
module.exports = {
target: ['web', 'es2017'],
};
Webpack'i, modern bir ES modülleri ortamını hedeflerken gereksiz sarmalayıcı işlevlerini atlayan optimize edilmiş paketler oluşturacak şekilde yapılandırmak da mümkündür. Bu işlem, webpack'i <script type="module">
kullanarak kod bölme paketlerini yükleyecek şekilde de yapılandırır.
module.exports = {
target: ['web', 'es2017'],
output: {
module: true,
},
experiments: {
outputModule: true,
},
};
Optimize Plugin ve BabelEsmPlugin gibi eski tarayıcıları desteklemeye devam ederken modern JavaScript'i derleyip yayınlamayı mümkün kılan çeşitli webpack eklentileri vardır.
Optimize Eklentisi
Optimize eklentisi, her bir kaynak dosya yerine nihai paketlenmiş kodu modern JavaScript'den eski JavaScript'e dönüştüren bir webpack eklentisidir. Bu, webpack yapılandırmanızın her şeyin modern JavaScript olduğunu varsaymasına olanak tanıyan, birden fazla çıkış veya söz dizimi için özel dallanma içermeyen bağımsız bir kurulumdur.
Optimize Plugin, tek tek modüller yerine paketler üzerinde çalıştığından uygulamanızın kodunu ve bağımlılarınızı eşit şekilde işler. Bu sayede, npm'deki modern JavaScript bağımlılıkları güvenli bir şekilde kullanılabilir. Çünkü bu bağımlılıkların kodları paketlenir ve doğru söz dizimine dönüştürülür. Ayrıca, modern ve eski tarayıcılar için ayrı paketler oluştururken iki derleme adımı içeren geleneksel çözümlerden daha hızlı olabilir. İki paket grubu, modül/modül yok kalıbı kullanılarak yüklenecek şekilde tasarlanmıştır.
// webpack.config.js
const OptimizePlugin = require('optimize-plugin');
module.exports = {
// ...
plugins: [new OptimizePlugin()],
};
Optimize Plugin
, genellikle modern ve eski kodu ayrı olarak paketleyen özel webpack yapılandırmalarından daha hızlı ve verimli olabilir. Ayrıca Babel'i sizin için çalıştırır ve modern ile eski çıkışlar için ayrı optimal ayarlarla Terser'i kullanarak paketleri en aza indirir. Son olarak, oluşturulan eski paketlerin ihtiyaç duyduğu polyfill'ler, yeni tarayıcılarda hiçbir zaman kopyalanmayacak veya gereksiz yere yüklenmeyecek şekilde özel bir komut dosyasına ayıklanır.
BabelEsmPlugin
BabelEsmPlugin, modern tarayıcılara daha az derlenmiş kod göndermek için mevcut paketlerin modern sürümlerini oluşturmak amacıyla @babel/preset-env ile birlikte çalışan bir webpack eklentisidir. module/nomodule için hazır en popüler çözümdür. Next.js ve Preact CLI tarafından kullanılır.
// webpack.config.js
const BabelEsmPlugin = require('babel-esm-plugin');
module.exports = {
//...
module: {
rules: [
// your existing babel-loader configuration:
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
plugins: [new BabelEsmPlugin()],
};
BabelEsmPlugin
, uygulamanızın büyük ölçüde ayrı iki derlemesini çalıştırdığından çok çeşitli webpack yapılandırmalarını destekler. Büyük uygulamalarda iki kez derleme işlemi biraz daha fazla zaman alabilir. Ancak bu teknik, BabelEsmPlugin
'ün mevcut webpack yapılandırmalarına sorunsuz bir şekilde entegre edilmesine olanak tanır ve bu yöntemi mevcut en kullanışlı seçeneklerden biri haline getirir.
node_modules dosyalarını derleyebilmesi için babel-loader'ı yapılandırma
babel-loader
'ü önceki iki eklentiden biri olmadan kullanıyorsanız modern JavaScript npm modüllerini kullanmak için önemli bir adım uygulamanız gerekir. İki ayrı babel-loader
yapılandırması tanımlamak, node_modules
'da bulunan modern dil özelliklerini ES2017'ye otomatik olarak derleyebilmenizi sağlar. Bu sırada kendi birinci taraf kodunuzu, projenizin yapılandırmasında tanımlanan Babel eklentileri ve hazır ayarlarıyla derleyebilirsiniz. Bu, modül/modülsüz kurulum için modern ve eski paketler oluşturmaz ancak eski tarayıcılarda sorun oluşturmadan modern JavaScript içeren npm paketlerini yükleyip kullanmayı mümkün kılar.
webpack-plugin-modern-npm, package.json
içinde "exports"
alanı bulunan npm bağımlılıkları derlemek için bu tekniği kullanır. Bu bağımlılıklar modern söz dizimi içerebilir:
// webpack.config.js
const ModernNpmPlugin = require('webpack-plugin-modern-npm');
module.exports = {
plugins: [
// auto-transpile modern stuff found in node_modules
new ModernNpmPlugin(),
],
};
Alternatif olarak, çözülmekte olan modüllerin package.json
alanında "exports"
alanı olup olmadığını kontrol ederek bu tekniği webpack yapılandırmanızda manuel olarak uygulayabilirsiniz. Özetlemek amacıyla önbelleğe alma işlemini atlayarak özel bir uygulama aşağıdaki gibi görünebilir:
// webpack.config.js
module.exports = {
module: {
rules: [
// Transpile for your own first-party code:
{
test: /\.js$/i,
loader: 'babel-loader',
exclude: /node_modules/,
},
// Transpile modern dependencies:
{
test: /\.js$/i,
include(file) {
let dir = file.match(/^.*[/\\]node_modules[/\\](@.*?[/\\])?.*?[/\\]/);
try {
return dir && !!require(dir[0] + 'package.json').exports;
} catch (e) {}
},
use: {
loader: 'babel-loader',
options: {
babelrc: false,
configFile: false,
presets: ['@babel/preset-env'],
},
},
},
],
},
};
Bu yaklaşımı kullanırken, modern söz dizimi özelliğinin sıkıştırıcınız tarafından desteklendiğinden emin olmanız gerekir. Hem Terser hem de uglify-es, sıkıştırma ve biçimlendirme sırasında ES2017 söz dizimini korumak ve bazı durumlarda oluşturmak için {ecma: 2017}
belirtme seçeneğine sahiptir.
Toplayıcı
Rollup, tek bir derleme kapsamında birden fazla paket grubu oluşturmak için yerleşik desteğe sahiptir ve varsayılan olarak modern kod oluşturur. Sonuç olarak, birleştirme, muhtemelen halihazırda kullandığınız resmi eklentilerle modern ve eski paketler oluşturacak şekilde yapılandırılabilir.
@rollup/plugin-babel
Rollup kullanıyorsanız getBabelOutputPlugin()
yöntemi (Rollup'un resmi Babel eklentisi tarafından sağlanır) kodu tek tek kaynak modüller yerine oluşturulan paketlerde dönüştürür.
Birleştirme, tek bir derlemenin parçası olarak her biri kendi eklentilerine sahip birden fazla paket grubu oluşturmak için yerleşik destek sunar. Bu özelliği kullanarak her birini farklı bir Babel çıkış eklentisi yapılandırmasından geçirerek modern ve eski için farklı paketler oluşturabilirsiniz:
// rollup.config.js
import {getBabelOutputPlugin} from '@rollup/plugin-babel';
export default {
input: 'src/index.js',
output: [
// modern bundles:
{
format: 'es',
plugins: [
getBabelOutputPlugin({
presets: [
[
'@babel/preset-env',
{
targets: {esmodules: true},
bugfixes: true,
loose: true,
},
],
],
}),
],
},
// legacy (ES5) bundles:
{
format: 'amd',
entryFileNames: '[name].legacy.js',
chunkFileNames: '[name]-[hash].legacy.js',
plugins: [
getBabelOutputPlugin({
presets: ['@babel/preset-env'],
}),
],
},
],
};
Ek derleme araçları
Rollup ve webpack, yüksek oranda yapılandırılabilirdir. Bu da genellikle her projenin, bağımlılıklarda modern JavaScript söz dizimini etkinleştirmek için yapılandırmasını güncellemesi gerektiği anlamına gelir. Parcel, Snowpack, Vite ve WMR gibi, yapılandırma yerine gelenek ve varsayılanları tercih eden daha üst düzey derleme araçları da vardır. Bu araçların çoğu, npm bağımlılıkları modern söz dizimi içerebileceğini varsayar ve üretim için derleme yaparken bunları uygun söz dizimi düzeylerine dönüştürür.
Webpack ve Rollup için özel eklentilere ek olarak, eski yedekleri olan modern JavaScript paketleri, devrim kullanılarak herhangi bir projeye eklenebilir. Devolution, bir derleme sisteminden gelen çıkışı eski JavaScript varyantları oluşturacak şekilde dönüştüren bağımsız bir araçtır. Bu araç, paketlemenin ve dönüşümlerin modern bir çıkış hedefi almasını sağlar.