Kontrolü Koruyun: Web Paketi ve Tepki Kılavuzu, Pt. 1
Yayınlanan: 2022-03-11Yeni bir React projesine başlarken, aralarından seçim yapabileceğiniz birçok şablonunuz vardır: React App Oluştur, react-boilerplate
ve React Starter Kit, bunlardan birkaçını sayabiliriz.
Binlerce geliştirici tarafından benimsenen bu şablonlar, çok büyük ölçekte uygulama geliştirmeyi destekleyebilmektedir. Ancak geliştirici deneyimini ve çıktıları çeşitli varsayılanlarla birleştirilmiş halde bırakırlar ve bu ideal olmayabilir.
Oluşturma süreciniz üzerinde daha fazla kontrol sahibi olmak istiyorsanız, özel bir Web paketi yapılandırmasına yatırım yapmayı seçebilirsiniz. Bu Web paketi öğreticisinden öğreneceğiniz gibi, bu görev çok karmaşık değildir ve bilgi, diğer kişilerin yapılandırmalarında sorun giderirken bile yararlı olabilir.
Web paketi: Başlarken
Bugün JavaScript'i yazma şeklimiz, tarayıcının çalıştırabileceği koddan farklıdır. Modern tarayıcılarda henüz desteklenmeyen başka tür kaynaklara, aktarılan dillere ve deneysel özelliklere sık sık güveniyoruz. Webpack, bu açığı kapatabilen ve geliştirici deneyimi söz konusu olduğunda hiçbir ücret ödemeden tarayıcılar arası uyumlu kod üretebilen JavaScript için bir modül paketleyicidir.
Başlamadan önce, bu Webpack eğitiminde sunulan tüm kodların GitHub'da eksiksiz bir Webpack/React örnek yapılandırma dosyası biçiminde de mevcut olduğunu unutmamalısınız. Lütfen orada atıfta bulunmaktan çekinmeyin ve herhangi bir sorunuz varsa bu makaleye geri dönün.
Temel Yapılandırma
Legato'dan (sürüm 4) beri, Webpack'in çalışması için herhangi bir yapılandırma gerekmez. Bir yapı modu seçmek, hedef ortama daha uygun bir dizi varsayılanı uygular. Bu makalenin ruhuna uygun olarak, bu varsayılanları bir kenara atacağız ve her hedef ortam için kendimiz için mantıklı bir yapılandırma uygulayacağız.
İlk olarak, webpack
ve webpack-cli
cli'yi kurmamız gerekiyor:
npm install -D webpack webpack-cli
Ardından webpack.config.js
aşağıdaki seçenekleri içeren bir yapılandırmayla doldurmamız gerekiyor:
-
devtool
: Geliştirme modunda kaynak haritası oluşturmayı etkinleştirir. -
entry
: React uygulamamızın ana dosyası. -
output.path
: Çıktı dosyalarının depolanacağı kök dizin. -
output.filename
: Oluşturulan dosyalar için kullanılacak dosya adı kalıbı. -
output.publicPath
: Dosyaların web sunucusunda konuşlandırılacağı kök dizinin yolu.
const path = require("path"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; const isDevelopment = !isProduction; return { devtool: isDevelopment && "cheap-module-source-map", entry: "./src/index.js", output: { path: path.resolve(__dirname, "dist"), filename: "assets/js/[name].[contenthash:8].js", publicPath: "/" } }; };
Yukarıdaki yapılandırma, düz JavaScript dosyaları için iyi çalışır. Ancak Webpack ve React kullanırken, kodu kullanıcılarımıza göndermeden önce ek dönüşümler yapmamız gerekecek. Bir sonraki bölümde, Webpack'in JavaScript dosyalarını yükleme şeklini değiştirmek için Babel'i kullanacağız.
JS Yükleyici
Babel, kod dönüştürme için birçok eklentiye sahip bir JavaScript derleyicisidir. Bu bölümde, onu Web paketi yapılandırmamıza bir yükleyici olarak tanıtacağız ve modern JavaScript kodunu yaygın tarayıcılar tarafından anlaşılacak şekilde dönüştürmek için yapılandıracağız.
İlk önce babel-loader
ve @babel/core
yüklememiz gerekecek:
npm install -D @babel/core babel-loader
Ardından Webpack yapılandırmamıza bir module
bölümü ekleyerek babel-loader
loader'ı JavaScript dosyalarını yüklemekten sorumlu hale getireceğiz:
@@ -11,6 +11,25 @@ module.exports = function(_env, argv) { path: path.resolve(__dirname, "dist"), filename: "assets/js/[name].[contenthash:8].js", publicPath: "/" + }, + module: { + rules: [ + { + test: /\.jsx?$/, + exclude: /node_modules/, + use: { + loader: "babel-loader", + options: { + cacheDirectory: true, + cacheCompression: false, + envName: isProduction ? "production" : "development" + } + } + } + ] + }, + resolve: { + extensions: [".js", ".jsx"] } }; };
Babel'i ayrı bir yapılandırma dosyası olan babel.config.js
kullanarak yapılandıracağız. Aşağıdaki özellikleri kullanacaktır:
-
@babel/preset-env
: Modern JavaScript özelliklerini geriye dönük uyumlu koda dönüştürür. -
@babel/preset-react
: JSX sözdizimini düz vanilya JavaScript işlev çağrılarına dönüştürür. -
@babel/plugin-transform-runtime
: Babel yardımcılarını paylaşılan modüllere ayıklayarak kod tekrarını azaltır. -
@babel/plugin-syntax-dynamic-import
: YerelPromise
desteği olmayan tarayıcılarda dinamikimport()
sözdizimini etkinleştirir. -
@babel/plugin-proposal-class-properties
: Sınıf tabanlı React bileşenleri yazmak için genel örnek alanı sözdizimi önerisi desteğini etkinleştirir.
Ayrıca birkaç React'e özel üretim optimizasyonunu etkinleştireceğiz:
-
babel-plugin-transform-react-remove-prop-types
kaldırır. -
@babel/plugin-transform-react-inline-elements
, derleme sırasındaReact.createElement
öğesini değerlendirir ve sonucu satır içine alır. -
@babel/plugin-transform-react-constant-elements
, statik React öğelerini sabitler olarak çıkarır.
Aşağıdaki komut gerekli tüm bağımlılıkları kuracaktır:
npm install -D @babel/preset-env @babel/preset-react @babel/runtime @babel/plugin-transform-runtime @babel/plugin-syntax-dynamic-import @babel/plugin-proposal-class-properties babel-plugin-transform-react-remove-prop-types @babel/plugin-transform-react-inline-elements @babel/plugin-transform-react-constant-elements
Ardından babel.config.js
şu ayarlarla dolduracağız:
module.exports = { presets: [ [ "@babel/preset-env", { modules: false } ], "@babel/preset-react" ], plugins: [ "@babel/plugin-transform-runtime", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-proposal-class-properties" ], env: { production: { only: ["src"], plugins: [ [ "transform-react-remove-prop-types", { removeImport: true } ], "@babel/plugin-transform-react-inline-elements", "@babel/plugin-transform-react-constant-elements" ] } } };
Bu yapılandırma, modern JavaScript'i tüm ilgili tarayıcılarla uyumlu bir şekilde yazmamızı sağlar. Aşağıdaki bölümlerde ele alacağımız bir React uygulamasında ihtiyaç duyabileceğimiz başka kaynak türleri de vardır.
CSS Yükleyici
React uygulamalarını şekillendirmeye gelince, en azından düz CSS dosyalarını dahil edebilmemiz gerekiyor. Bunu Webpack'te aşağıdaki yükleyicileri kullanarak yapacağız:
-
css-loader
: Görüntüler, yazı tipleri ve ek stil içe aktarmaları gibi harici kaynakları çözerek CSS dosyalarını ayrıştırır. -
style-loader
: Geliştirme sırasında, çalışma zamanında belgeye yüklenen stilleri enjekte eder. -
mini-css-extract-plugin
: Tarayıcı önbelleğinden yararlanmak için, üretim amaçlı kullanım için yüklenen stilleri ayrı dosyalara çıkarır.
Yukarıdaki CSS yükleyicilerini yükleyelim:
npm install -D css-loader style-loader mini-css-extract-plugin
Ardından Webpack yapılandırmamızın module.rules
bölümüne yeni bir kural ekleyeceğiz:
@@ -1,4 +1,5 @@ const path = require("path"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -25,6 +26,13 @@ module.exports = function(_env, argv) { envName: isProduction ? "production" : "development" } } + }, + { + test: /\.css$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : "style-loader", + "css-loader" + ] } ] },
Ayrıca, yalnızca üretim modunda etkinleştireceğimiz plugins
bölümüne MiniCssExtractPlugin
ekleyeceğiz:
@@ -38,6 +38,13 @@ module.exports = function(_env, argv) { }, resolve: { extensions: [".js", ".jsx"] - } + }, + plugins: [ + isProduction && + new MiniCssExtractPlugin({ + filename: "assets/css/[name].[contenthash:8].css", + chunkFilename: "assets/css/[name].[contenthash:8].chunk.css" + }) + ].filter(Boolean) }; };
Bu yapılandırma, düz CSS dosyaları için çalışır ve bir sonraki makalede tartışacağımız Sass ve PostCSS gibi çeşitli CSS işlemcileriyle çalışacak şekilde genişletilebilir.
Görüntü Yükleyici
Web paketi ayrıca resimler, videolar ve diğer ikili dosyalar gibi statik kaynakları yüklemek için de kullanılabilir. Bu tür dosyaları ele almanın en genel yolu, tüketicilerine gerekli kaynaklar için bir URL referansı sağlayacak olan file-loader
veya url-loader
kullanmaktır.
Bu bölümde, yaygın görüntü formatlarını işlemek için url-loader
ekleyeceğiz. url-loader
file-loader
loader'dan ayıran şey, orijinal dosyanın boyutu belirli bir eşikten küçükse, tüm dosyayı URL'ye base64 kodlu içerik olarak gömmesi ve böylece ek bir istek ihtiyacını ortadan kaldırmasıdır.
İlk önce url-loader
:
npm install -D url-loader
Ardından Webpack yapılandırmamızın module.rules
bölümüne yeni bir kural ekliyoruz:
@@ -34,6 +34,16 @@ module.exports = function(_env, argv) { isProduction ? MiniCssExtractPlugin.loader : "style-loader", "css-loader" ] + }, + { + test: /\.(png|jpg|gif)$/i, + use: { + loader: "url-loader", + options: { + limit: 8192, + name: "static/media/[name].[hash:8].[ext]" + } + } } ] },
SVG
SVG görüntüleri için, içe aktarılan dosyaları React bileşenlerine dönüştüren @svgr/webpack
yükleyicisini kullanacağız.
@svgr/webpack
:
npm install -D @svgr/webpack
Ardından Webpack yapılandırmamızın module.rules
bölümüne yeni bir kural ekliyoruz:
@@ -44,6 +44,10 @@ module.exports = function(_env, argv) { name: "static/media/[name].[hash:8].[ext]" } } + }, + { + test: /\.svg$/, + use: ["@svgr/webpack"] } ] },
React bileşenleri olarak SVG görüntüleri kullanışlı olabilir ve @svgr/webpack
, SVGO kullanarak optimizasyon gerçekleştirir.

Not: Belirli animasyonlar ve hatta fareyle üzerine gelme efektleri için JavaScript kullanarak SVG'yi değiştirmeniz gerekebilir. Neyse ki @svgr/webpack
, SVG içeriğini varsayılan olarak JavaScript paketine gömer ve bunun için gereken güvenlik kısıtlamalarını atlamanıza olanak tanır.
dosya yükleyici
Diğer dosya türlerine başvurmamız gerektiğinde, genel file-loader
işi yapacaktır. url-loader
benzer şekilde çalışır, onu gerektiren koda bir varlık URL'si sağlar, ancak onu optimize etmek için hiçbir girişimde bulunmaz.
Her zaman olduğu gibi önce Node.js modülünü kuruyoruz. Bu durumda, file-loader
:
npm install -D file-loader
Ardından Webpack yapılandırmamızın module.rules
bölümüne yeni bir kural ekliyoruz. Örneğin:
@@ -48,6 +48,13 @@ module.exports = function(_env, argv) { { test: /\.svg$/, use: ["@svgr/webpack"] + }, + { + test: /\.(eot|otf|ttf|woff|woff2)$/, + loader: require.resolve("file-loader"), + options: { + name: "static/media/[name].[hash:8].[ext]" + } } ] },
Buraya yazı tiplerini yüklemek için CSS dosyalarınızdan başvurabileceğiniz file-loader
ekledik. Bu örneği, ihtiyacınız olan diğer dosya türlerini yüklemek için genişletebilirsiniz.
Çevre Eklentisi
Yapı ortamından uygulama kodumuza ortam değişkenlerini göstermek için DefinePlugin()
kullanabiliriz. Örneğin:
@@ -1,5 +1,6 @@ const path = require("path"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const webpack = require("webpack"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -65,7 +66,12 @@ module.exports = function(_env, argv) { new MiniCssExtractPlugin({ filename: "assets/css/[name].[contenthash:8].css", chunkFilename: "assets/css/[name].[contenthash:8].chunk.css" - }) + }), + new webpack.DefinePlugin({ + "process.env.NODE_ENV": JSON.stringify( + isProduction ? "production" : "development" + ) + }) ].filter(Boolean) }; };
Burada process.env.NODE_ENV
inşa modunu temsil eden bir dizeyle değiştirdik: "development"
veya "production"
.
HTML Eklentisi
Bir index.html
dosyasının yokluğunda, JavaScript paketimiz işe yaramaz, kimse onu bulamaz. Bu bölümde, bizim için bir HTML dosyası oluşturmak için html-webpack-plugin
tanıtacağız.
html-webpack-plugin
:
npm install -D html-webpack-plugin
Ardından Webpack yapılandırmamızın plugins
bölümüne html-webpack-plugin
ekliyoruz:
@@ -1,6 +1,7 @@ const path = require("path"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const webpack = require("webpack"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -71,6 +72,10 @@ module.exports = function(_env, argv) { "process.env.NODE_ENV": JSON.stringify( isProduction ? "production" : "development" ) + }), + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "public/index.html"), + inject: true }) ].filter(Boolean) };
Oluşturulan public/index.html
dosyası paketimizi yükleyecek ve uygulamamızı önyükleyecektir.
optimizasyon
Oluşturma sürecimizde kullanabileceğimiz birkaç optimizasyon tekniği var. Paketimizin boyutunu işlevsellik açısından hiçbir ücret ödemeden küçültebileceğimiz bir süreç olan kod küçültme ile başlayacağız. terser-webpack-plugin
webpack-plugin ve CSS için optimize-css-assets-webpack-plugin
.
Bunları yükleyelim:
npm install -D terser-webpack-plugin optimize-css-assets-webpack-plugin
Ardından yapılandırmamıza bir optimization
bölümü ekleyeceğiz:
@@ -2,6 +2,8 @@ const path = require("path"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); +const TerserWebpackPlugin = require("terser-webpack-plugin"); +const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -75,6 +77,27 @@ module.exports = function(_env, argv) { isProduction ? "production" : "development" ) }) - ].filter(Boolean) + ].filter(Boolean), + optimization: { + minimize: isProduction, + minimizer: [ + new TerserWebpackPlugin({ + terserOptions: { + compress: { + comparisons: false + }, + mangle: { + safari10: true + }, + output: { + comments: false, + ascii_only: true + }, + warnings: false + } + }), + new OptimizeCssAssetsPlugin() + ] + } }; };
Yukarıdaki ayarlar, tüm modern tarayıcılarla kod uyumluluğu sağlayacaktır.
Kod Bölme
Kod bölme, uygulamamızın performansını artırmak için kullanabileceğimiz başka bir tekniktir. Kod bölme, iki farklı yaklaşıma atıfta bulunabilir:
- Bir dinamik
import()
ifadesi kullanarak, paket boyutumuzun önemli bir bölümünü oluşturan uygulama parçalarını ayıklayabilir ve bunları talep üzerine yükleyebiliriz. - Tarayıcı önbelleğinden yararlanmak ve tekrar ziyaret edenler için performansı artırmak için daha az sıklıkta değişen kodu ayıklayabiliriz.
Web paketi yapılandırmamızın optimization.splitChunks
bölümünü, üçüncü taraf bağımlılıklarını ve ortak parçaları ayrı dosyalara çıkarmak için ayarlarla dolduracağız:
@@ -99,7 +99,29 @@ module.exports = function(_env, argv) { sourceMap: true }), new OptimizeCssAssetsPlugin() - ] + ], + splitChunks: { + chunks: "all", + minSize: 0, + maxInitialRequests: 20, + maxAsyncRequests: 20, + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + name(module, chunks, cacheGroupKey) { + const packageName = module.context.match( + /[\\/]node_modules[\\/](.*?)([\\/]|$)/ + )[1]; + return `${cacheGroupKey}.${packageName.replace("@", "")}`; + } + }, + common: { + minChunks: 2, + priority: -10 + } + } + }, + runtimeChunk: "single" } }; };
Burada kullandığımız seçeneklere daha yakından bakalım:
-
chunks: "all"
: Varsayılan olarak, ortak yığın çıkarma yalnızca dinamikimport()
ile yüklenen modülleri etkiler. Bu ayar, giriş noktası yüklemesi için de optimizasyon sağlar. -
minSize: 0
: Varsayılan olarak, yalnızca belirli bir boyut eşiğinin üzerindeki parçalar ayıklama için uygun hale gelir. Bu ayar, boyutundan bağımsız olarak tüm yaygın kodlar için optimizasyon sağlar. -
maxInitialRequests: 20
vemaxAsyncChunks: 20
: Bu ayarlar, sırasıyla giriş noktası içe aktarmaları ve ayrık nokta içe aktarmaları için paralel olarak yüklenebilecek maksimum kaynak dosya sayısını artırır.
Ek olarak, aşağıdaki cacheGroups
yapılandırmasını belirtiyoruz:
-
vendors
: Üçüncü taraf modüller için çıkarmayı yapılandırır.-
test: /[\\/]node_modules[\\/]/
: Eşleşen üçüncü taraf bağımlılıkları için dosya adı kalıbı. -
name(module, chunks, cacheGroupKey)
: Aynı modülden ayrılan parçaları ortak bir ad vererek gruplandırır.
-
-
common
: Uygulama kodundan ortak parça çıkarmayı yapılandırır.-
minChunks: 2
: En az iki modülden referans alınırsa, bir yığın ortak kabul edilecektir. -
priority: -10
: İlk olarakvendors
önbellek grubuna yönelik yığınların dikkate alınması içincommon
önbellek grubuna negatif bir öncelik atar.
-
Ayrıca, runtimeChunk: "single"
belirterek, Webpack çalışma zamanı kodunu birden çok giriş noktası arasında paylaşılabilen tek bir yığın halinde ayıklıyoruz.
Geliştirici Sunucusu
Şimdiye kadar, uygulamamızın üretim yapısını oluşturmaya ve optimize etmeye odaklandık, ancak Webpack ayrıca, geliştirme sürecinde bize yardımcı olacak canlı yeniden yükleme ve hata raporlama özelliğine sahip kendi web sunucusuna sahiptir. Adı webpack-dev-server
ve ayrı olarak kurmamız gerekiyor:
npm install -D webpack-dev-server
Bu pasajda, Webpack yapılandırmamıza bir devServer
bölümü sunuyoruz:
@@ -120,6 +120,12 @@ module.exports = function(_env, argv) { } }, runtimeChunk: "single" + }, + devServer: { + compress: true, + historyApiFallback: true, + open: true, + overlay: true } }; };
Burada aşağıdaki seçenekleri kullandık:
-
compress: true
: Daha hızlı yeniden yüklemeler için varlık sıkıştırmasını etkinleştirir. -
historyApiFallback: true
: Geçmişe dayalı yönlendirme içinindex.html
geri dönüşü etkinleştirir. -
open: true
: Geliştirme sunucusunu başlattıktan sonra tarayıcıyı açar. -
overlay: true
: Tarayıcı penceresinde Web paketi hatalarını görüntüler.
API isteklerini arka uç sunucusuna iletmek için proxy ayarlarını yapılandırmanız da gerekebilir.
Webpack ve React: Performans açısından optimize edilmiş ve Hazır!
Webpack ile çeşitli kaynak türlerinin nasıl yükleneceğini, Webpack'in bir geliştirme ortamında nasıl kullanılacağını ve bir üretim yapısını optimize etmek için çeşitli teknikleri öğrendik. Gerekirse, kendi React/Webpack kurulumunuz için ilham almak için tam yapılandırma dosyasını her zaman inceleyebilirsiniz. Bu tür becerileri geliştirmek, React geliştirme hizmetleri sunan herkes için standart bir ücrettir.
Bu serinin bir sonraki bölümünde, TypeScript kullanımı, CSS ön işlemcileri ve sunucu tarafı oluşturma ve ServiceWorker'ları içeren gelişmiş optimizasyon teknikleri dahil olmak üzere daha özel kullanım durumları için talimatlarla bu yapılandırmayı genişleteceğiz. React uygulamanızı üretime geçirmek için Webpack hakkında bilmeniz gereken her şeyi öğrenmek için bizi izlemeye devam edin.