Kontrolü Koruyun: Web Paketi ve Tepki Kılavuzu, Pt. 1

Yayınlanan: 2022-03-11

Yeni 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 : Yerel Promise desteği olmayan tarayıcılarda dinamik import() 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ında React.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:

  1. 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.
  2. 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 dinamik import() 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 ve maxAsyncChunks: 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 olarak vendors önbellek grubuna yönelik yığınların dikkate alınması için common ö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çin index.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.