Webpack, öğeleri önbelleğe almaya nasıl yardımcı olur?
Uygulamanız gereken bir sonraki adım (uygulama boyutunu optimize ettikten uygulamanın önbelleğe alma süresini iyileştirir. Uygulamanın bazı kısımlarını kullanmak için ve her defasında yeniden indirmekten kaçınabilir.
Paket sürümü belirleme ve önbellek üstbilgilerini kullanma
Önbelleğe alma işlemi için genel yaklaşım şu şekildedir:
tarayıcıya bir dosyayı çok uzun bir süre (ör. bir yıl) için önbelleğe almasını söyler:
# Server header Cache-Control: max-age=31536000
Cache-Control
uygulamasının işlevini bilmiyorsanız Jake Archibald'ın en iyi önbelleğe alma konusunda mükemmel kayıt öğrenin.ve yeniden indirmeyi zorunlu kılmak için değiştirildiğinde dosyayı yeniden adlandırın:
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
Bu yaklaşım, tarayıcıya JS dosyasını indirmesini, önbelleğe almasını ve önbelleğe alınmış kopya. Tarayıcı, yalnızca dosya adı değişirse ağa bağlanır (veya bir yıl geçerse).
Webpack ile de aynısını yaparsınız ancak bir sürüm numarası yerine
dosya karma değeri. Karma değeri dosya adına eklemek için
[chunkhash]
:
// webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.[chunkhash].js' // → bundle.8e0d62a03.js
}
};
Gerektiğinde
dosyayı istemciye göndermek için HtmlWebpackPlugin
veya
WebpackManifestPlugin
.
HtmlWebpackPlugin
, bir
ama daha az esnek bir yaklaşım izler. Derleme sırasında bu eklenti
Tüm derlenmiş kaynakları içeren HTML dosyası. Sunucu mantığınız
karmaşıksa sizin için yeterli olacaktır:
<!-- index.html -->
<!DOCTYPE html>
<!-- ... -->
<script src="bundle.8e0d62a03.js"></script>
İlgili içeriği oluşturmak için kullanılan
WebpackManifestPlugin
Karmaşık bir sunucu parçanız varsa kullanışlı olan daha esnek bir yaklaşımdır.
Derleme sırasında, dosya adları arasında eşleme içeren bir JSON dosyası oluşturur.
karma olmadan ve karma ile dosya adları olmadan. Öğrenmek için sunucuda bu JSON kullanın
hangi dosyayla çalışacak:
// manifest.json
{
"bundle.js": "bundle.8e0d62a03.js"
}
Daha fazla bilgi
- Jake Archibald en iyi önbelleğe alma hakkında uygulamalar
Bağımlılıkları ve çalışma zamanını ayrı bir dosyaya çıkarın
Bağımlılıklar
Uygulama bağımlılıkları genellikle gerçek uygulama kodundan daha az değişir. Taşınırsanız ayrı bir dosyada toplarsanız, tarayıcı bunları ayrı ayrı önbelleğe alabilir: ve uygulama kodu her değiştiğinde bunları yeniden indirmez.
Bağımlılıkları ayrı bir parçaya ayıklamak için üç adımı uygulayın:
Çıkış dosya adını
[name].[chunkname].js
ile değiştirin:// webpack.config.js module.exports = { output: { // Before filename: 'bundle.[chunkhash].js', // After filename: '[name].[chunkhash].js' } };
Web paketi, uygulamayı derlediğinde
[name]
'in yerini alır olduğunu görebilirsiniz.[name]
bölümünü eklemezsek parçalarını birbirinden ayırt etmek oldukça zor.entry
alanını nesneye dönüştürün:// webpack.config.js module.exports = { // Before entry: './index.js', // After entry: { main: './index.js' } };
Bu snippet'te, "main" bir parçanın adıdır. Bu ad,
[name]
yerine 1. adımdaki talimatları uygulayın.Şu ana kadar uygulamayı derlerseniz bu parça, uygulama kodunun tamamını içerecektir. yapmadığımızı düşünün. Ancak bu süre içinde değişecek.
Web paketi 4'te,
optimization.splitChunks.chunks: 'all'
seçeneğini ekleyin web paketi yapılandırmanıza ekleyin:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
Bu seçenek, akıllı kod bölmeyi etkinleştirir. Bu öğeyle, webpack aşağıdaki durumlarda tedarikçi kodunu ayıklar: 30 kB'tan büyük olur (küçültme ve gzip'ten önce). Ayrıca, genel kodu da çıkarır. Bu, derlemeniz birkaç paket (ör. uygulamanızı rotalara ayırırsanız).
Web paketi 3'te
CommonsChunkPlugin
etiketini ekleyin:// webpack.config.js (for webpack 3) module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin({ // A name of the chunk that will include the dependencies. // This name is substituted in place of [name] from step 1 name: 'vendor', // A function that determines which modules to include into this chunk minChunks: module => module.context && module.context.includes('node_modules'), }) ] };
Bu eklenti, yollarında
node_modules
ve bunlarıvendor.[chunkhash].js
adlı ayrı bir dosyaya taşır.
Bu değişikliklerden sonra, her derleme bir yerine iki dosya oluşturur: main.[chunkhash].js
ve
vendor.[chunkhash].js
(web paketi 4 için vendors~main.[chunkhash].js
). Webpack 4'te ise
bağımlılıklar küçükse tedarikçi paketi oluşturulmayabilir. Bu sorun değil:
$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
Asset Size Chunks Chunk Names
./main.00bab6fd3100008a42b0.js 82 kB 0 [emitted] main
./vendor.d9e134771799ecdf9483.js 47 kB 1 [emitted] vendor
Tarayıcı bu dosyaları ayrı olarak önbelleğe alır ve yalnızca değişen kodu yeniden indirir.
Webpack çalışma zamanı kodu
Maalesef yalnızca tedarikçi firma kodunu ayıklamak yeterli değildir. Örneğin uygulama kodunda bir şeyi değiştirin:
// index.js
…
…
// E.g. add this:
console.log('Wat');
vendor
karmasının da değiştiğini görürsünüz:
Asset Size Chunks Chunk Names
./vendor.d9e134771799ecdf9483.js 47 kB 1 [emitted] vendor
↓
Asset Size Chunks Chunk Names
./vendor.e6ea4504d61a1cc1c60b.js 47 kB 1 [emitted] vendor
Bunun nedeni, modüllerin kodlarından ayrı olarak web paketi paketinde bir çalışma zamanı – küçük bir kod parçasıdır tek bir yerden yönetin. Kodu birden fazla dosyaya böldüğünüzde parçası, parça kimlikleri ile değerleri ilgili dosyalar:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
Webpack, bu çalışma zamanını, vendor
olan son oluşturulan parçaya ekler.
bizim örneğimize dönelim. Bu kod parçası da her parça değiştiğinde, farklı bir kod
tüm vendor
yığınının değişmesine neden olur.
Bu sorunu çözmek için çalışma zamanını ayrı bir dosyaya taşıyalım. Webpack 4'te,
optimization.runtimeChunk
seçeneği etkinleştirildiğinde:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
runtimeChunk: true
}
};
Web paketi 3'te,bunu CommonsChunkPlugin
ile ekstra boş bir yığın oluşturarak yapın:
// webpack.config.js (for webpack 3)
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => module.context && module.context.includes('node_modules')
}),
// This plugin must come after the vendor one (because webpack
// includes runtime into the last chunk)
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
// minChunks: Infinity means that no app modules
// will be included into this chunk
minChunks: Infinity
})
]
};
Bu değişikliklerden sonra, her derleme üç dosya oluşturacaktır:
$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
Asset Size Chunks Chunk Names
./main.00bab6fd3100008a42b0.js 82 kB 0 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 1 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
Bu adımları ters sırayla index.html
öğesine ekleyin. Hepsi bu kadar:
<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
<script src="./vendor.26886caf15818fa82dfa.js"></script>
<script src="./main.00bab6fd3100008a42b0.js"></script>
Daha fazla bilgi
- Uzun vadeli önbelleğe alma hakkında web paketi kılavuzu
- Web paketi çalışma zamanı ve manifesto
- "Google Analytics'ten en iyi şekilde CommonsChunkPlugin"
optimization.splitChunks
veoptimization.runtimeChunk
nasıl çalışır?
Ekstra HTTP isteğini kaydetmek için satır içi web paketi çalışma zamanı
İşleri daha da iyi hale getirmek için web paketi çalışma zamanını HTML koduna satır içi olarak eklemeyi deneyin. tıklayın. Örneğin, bunun yerine:
<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
şunu yap:
<!-- index.html -->
<script>
!function(e){function n(r){if(t[r])return t[r].exports;…}} ([]);
</script>
Çalışma zamanı küçüktür ve bunu satır içi yapmak bir HTTP isteğini kaydetmenize yardımcı olur (halihazırda HTTP/1 ile önemlidir; HTTP/2 ile daha az önemli olsa da etkisi).
Bunu nasıl yapacağınız aşağıda açıklanmıştır.
HTMLWebpackEklentileri ile HTML oluşturursanız
URL'yi HtmlWebpackPlugin'in bir HTML dosyası, InlineSourcePlugin tek ihtiyacınız olan şey:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
inlineSource: 'runtime~.+\\.js',
}),
new InlineSourcePlugin()
]
};
Özel bir sunucu mantığı kullanarak HTML oluşturursanız
Webpack 4 ile:
URL'yi
WebpackManifestPlugin
çalışma zamanı parçasının oluşturulan adını öğrenmek için aşağıdaki adımları uygulayın:// webpack.config.js (for webpack 4) const ManifestPlugin = require('webpack-manifest-plugin'); module.exports = { plugins: [ new ManifestPlugin() ] };
Bu eklentiyle oluşturulan bir derleme, şuna benzeyen bir dosya oluşturur:
// manifest.json { "runtime~main.js": "runtime~main.8e0d62a03.js" }
Çalışma zamanı parçasının içeriğini uygun bir şekilde satır içine alın. Ör. Node.js ve Express ile:
// server.js const fs = require('fs'); const manifest = require('./manifest.json'); const runtimeContent = fs.readFileSync(manifest['runtime~main.js'], 'utf-8'); app.get('/', (req, res) => { res.send(` … <script>${runtimeContent}</script> … `); });
Veya webpack 3 ile:
filename
belirterek çalışma zamanı adını statik hale getirin:module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'runtime', minChunks: Infinity, filename: 'runtime.js' }) ] };
runtime.js
içeriğini uygun bir şekilde satır içine alın. Ör. Node.js ve Express ile:// server.js const fs = require('fs'); const runtimeContent = fs.readFileSync('./runtime.js', 'utf-8'); app.get('/', (req, res) => { res.send(` … <script>${runtimeContent}</script> … `); });
Şu anda ihtiyaç duymadığınız kodu geç yükleyin
Bazen bir sayfada daha fazla veya daha az önemli bölümler bulunur:
- YouTube'da bir video sayfası yüklerseniz videoya, içeriğin yorum. Bu durumda video, yorumlardan daha önemlidir.
- Bir haber sitesindeki bir makaleyi açtığınızda, o haberin içeriği hakkında daha çok reklamlardan daha iyi bir şekilde anlatacağım. Bu durumda metin reklamlardan daha önemlidir.
Bu gibi durumlarda, ilk yükleme performansını iyileştirmek için
geri kalan bölümleri daha sonra geç yükleyebilirsiniz.
import()
işlevi ve
code-splitting:
// videoPlayer.js
export function renderVideoPlayer() { … }
// comments.js
export function renderComments() { … }
// index.js
import {renderVideoPlayer} from './videoPlayer';
renderVideoPlayer();
// …Custom event listener
onShowCommentsClick(() => {
import('./comments').then((comments) => {
comments.renderComments();
});
});
import()
, belirli bir modülü dinamik olarak yüklemek istediğinizi belirtir. Zaman
webpack import('./module.js')
görür, bu modülü ayrı bir
chunk:
$ webpack
Hash: 39b2a53cb4e73f0dc5b2
Version: webpack 3.8.1
Time: 4273ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./main.f7e53d8e13e9a2745d6d.js 60 kB 1 [emitted] main
./vendor.4f14b6326a80f4752a98.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
ve yalnızca yürütme import()
işlevine ulaştığında indirir.
Bu işlem, main
paketini küçülterek ilk yükleme süresini iyileştirir.
Daha da iyisi, önbelleğe almayı iyileştirir. Ana parçadaki kodu değiştirirseniz
yorum yığını bundan etkilenmez.
Daha fazla bilgi
import()
için web paketi dokümanları işlevimport()
öğesinin uygulanmasına ilişkin JavaScript teklifi söz dizimi
Kodu rotalara ve sayfalara ayırın
Uygulamanızın birden fazla yolu veya sayfası varsa ancak
(tek bir main
parçası) muhtemelen bir sonraki
dikkat edin. Örneğin, bir kullanıcı sitenizin ana sayfasından birini ziyaret ettiğinde:
aynı web sitesindeki bir makaleyi oluşturmak için ancak sayfayı yüklerler. Ayrıca, kullanıcı her zaman sadece evi ziyaret ediyorsa ve makale kodunda bir değişiklik yaparsanız webpack, bütün uygulamayı indirecektir, ancak kullanıcının tüm uygulamayı yeniden indirmesi gerekecektir.
Uygulamayı sayfalara (veya tek sayfalık bir uygulamaysa rotalara) bölersek kullanıcı yalnızca ilgili kodu indirir. Ayrıca tarayıcı, uygulama kodunu önbelleğe alır. daha iyidir: ana sayfa kodunu değiştirirseniz webpack yalnızca parçasını oluşturur.
Tek sayfalık uygulamalar için
Tek sayfalık uygulamaları rotalara göre bölmek için import()
kullanın (Geç yükleme kodu
en az üç aylık reklam harcaması yapın." bölümünde bulabilirsiniz. Bir çerçeve kullanırsanız
bunun için zaten bir çözümü olabilir:
- "Kod
Bölme"
react-router
adlı kullanıcının dokümanlarında (React için) - "Geç Yükleme
Rotalar"
vue-router
adlı kullanıcının dokümanları (Vue.js için)
Geleneksel çok sayfalı uygulamalar için
Geleneksel uygulamaları sayfalara göre ayırmak için webpack'in girişini kullanın. puan. Uygulamanızda üç tane Bunlar ana sayfa, makale sayfası ve kullanıcı hesabı sayfası gibi üç giriş olmalıdır:
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
Webpack, her giriş dosyası için ayrı bir bağımlılık ağacı derler ve Yalnızca söz konusu girişin kullandığı modülleri içeren bir paket:
$ webpack
Hash: 318d7b8490a7382bf23b
Version: webpack 3.8.1
Time: 4273ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./home.91b9ed27366fe7e33d6a.js 18 kB 1 [emitted] home
./article.87a128755b16ac3294fd.js 32 kB 2 [emitted] article
./profile.de945dc02685f6166781.js 24 kB 3 [emitted] profile
./vendor.4f14b6326a80f4752a98.js 46 kB 4 [emitted] vendor
./runtime.318d7b8490a7382bf23b.js 1.45 kB 5 [emitted] runtime
Bu nedenle, yalnızca makale sayfasında Lodash kullanıyorsa home
ve profile
paketleri
yer almaz ve kullanıcının bu kitaplığı indirmesi gerekmez.
ana sayfayı ziyaret edin.
Ayrı bağımlılık ağaçlarının dezavantajları vardır. İki giriş noktası
Bağımlılıklarınızı bir tedarikçi paketine taşımadıysanız,
puanlar Lodash'in bir kopyasını içerir. Bu sorunu çözmek için webpack 4'te
optimization.splitChunks.chunks: 'all'
seçeneğini web paketi yapılandırmanıza ekleyin:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
Bu seçenek, akıllı kod bölmeyi etkinleştirir. Bu seçenekle webpack otomatik olarak ortak kodu arayın ve bunu ayrı dosyalara çıkarın.
Alternatif olarak, web paketi 3'te CommonsChunkPlugin
kullanın.
- ortak bağımlılıkları belirtilen yeni bir dosyaya taşır:
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2 // 2 is the default value
})
]
};
En iyi değeri bulmak için minChunks
değeriyle oynayabilirsiniz. Genellikle,
küçük tutmanız ama parçaların sayısı arttıkça artırın. Örneğin,
Örneğin, 3 parça için minChunks
2, 30 parça için 8 olabilir
Çünkü 2'de tutarsanız ortak dosyaya çok fazla modül eklenir,
çok fazla şişirirsiniz.
Daha fazla bilgi
- Giriş kavramıyla ilgili web paketi dokümanları puan
- Web paketi dokümanlarından CommonsChunkPlugin
- "Google Analytics'ten en iyi şekilde CommonsChunkPlugin"
optimization.splitChunks
veoptimization.runtimeChunk
nasıl çalışır?
Modül kimliklerini daha kararlı hale getirin
Webpack, kod oluştururken her modüle bir kimlik atar. Daha sonra, bu kimlikler
paketteki require()
saniye içinde kullanılıyor. Genellikle derleme çıktısında kimlikler görürsünüz
hemen önce:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./main.4e50a16675574df6a9e9.js 60 kB 1 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
↓ Burada
[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
[4] ./comments.js 58 kB {0} [built]
[5] ./ads.js 74 kB {1} [built]
+ 1 hidden module
Varsayılan olarak, kimlikler bir sayaç kullanılarak hesaplanır (yani ilk modülün kimliği 0, ikincisinin kimliği 1'dir, vb.). Bu sorun, yeni bir kampanyaya üzerinde değişiklik yaptığınızda, modül listesinin ortasında görünebilir ve sonraki modüllerin Kimlikler:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.5c82c0f337fcb22672b5.js 22 kB 0 [emitted]
./main.0c8b617dfc40c2827ae3.js 82 kB 1 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
↓ Sekmemize yeni bir modül...
[4] ./webPlayer.js 24 kB {1} [built]
↓ Ve neler yaptığına bakın! comments.js
artık 4 yerine 5 kimliğine sahip
[5] ./comments.js 58 kB {0} [built]
↓ ads.js
artık 5 yerine 6 kimliğine sahip
[6] ./ads.js 74 kB {1} [built]
+ 1 hidden module
Bu işlem, değişen kimlikleri olan modülleri içeren veya bunlara bağlı olan tüm parçaları geçersiz kılar:
korumayı sağlar. Örneğimizde 0
parçası (parça)
comments.js
ile birlikte) ve main
parçası (diğer uygulama koduyla yığın)
geçersiz kılınmıştır. Yalnızca main
için geçerli olması gerekirdi.
Bu sorunu çözmek için modül kimliklerinin
HashedModuleIdsPlugin
.
Sayaca dayalı kimlikleri, modül yollarının karmalarıyla değiştirir:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.6168aaac8461862eab7a.js 22.5 kB 0 [emitted]
./main.a2e49a279552980e3b91.js 60 kB 1 [emitted] main
./vendor.ff9f7ea865884e6a84c8.js 46 kB 2 [emitted] vendor
./runtime.25f5d0204e4f77fa57a1.js 1.45 kB 3 [emitted] runtime
↓ Burada
[3IRH] ./index.js 29 kB {1} [built]
[DuR2] (webpack)/buildin/global.js 488 bytes {2} [built]
[JkW7] (webpack)/buildin/module.js 495 bytes {2} [built]
[LbCc] ./webPlayer.js 24 kB {1} [built]
[lebJ] ./comments.js 58 kB {0} [built]
[02Tr] ./ads.js 74 kB {1} [built]
+ 1 hidden module
Bu yaklaşımda, bir modülün kimliği yalnızca söz konusu modülü yeniden adlandırırsanız veya taşırsanız modülünü kullanabilirsiniz. Yeni modüller diğer modüllerin çalışmasını etkilemeyecektir Kimlikler.
Etkinleştirmek için yapılandırmanın plugins
bölümüne ekleyin:
// webpack.config.js
module.exports = {
plugins: [
new webpack.HashedModuleIdsPlugin()
]
};
Daha fazla bilgi
- Web paketi dokümanlarından HashedModuleIdsPlugin
Özet
- Paketi önbelleğe alın ve paket adını değiştirerek sürümleri birbirinden ayırt edin
- Paketi uygulama kodu, tedarikçi firma kodu ve çalışma zamanına böl
- HTTP isteğini kaydetmek için çalışma zamanını satır içine alma
- Kritik olmayan kodu
import
ile geç yükleyin - Gereksiz öğeler yüklenmesini önlemek için kodu rotalara/sayfalara göre bölün