, :
optimization: {
splitChunks: {
chunks: 'all',
},
runtimeChunk: true,
}
vendors~ runtime~. Sokra splitChunks:
splitChunks: {
chunks: "async",
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
name: true,
cacheGroups: {
default: {
minChunks: 2,
priority: -20
reuseExistingChunk: true,
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
}
}
}
vendors default. , default.
, , PHP:
public static function webpack_asset($chunkName, $extensions=null, $media=false) {
static $stats;
if($stats === null) {
$stats = WxJson::loadFile(WX::$path.'/webpack.stats.json');
}
$paths = WXU::array_get($stats,['assetsByChunkName',$chunkName],false);
if($paths === false) {
throw new \Exception("webpack asset not found: $chunkName");
}
foreach($stats['assetsByChunkName'] as $cn => $files) {
if(self::EndsWith($cn, '~' . $chunkName)) {
$paths = array_merge($files, $paths);
}
}
$html = [];
foreach((array)$paths as $p) {
$ext = WXU::GetFileExt($p);
if($extensions) {
if(is_array($extensions)) {
if(!in_array($ext,$extensions)) {
continue;
}
} elseif(is_string($extensions)) {
if($ext !== $extensions) {
continue;
}
} else {
throw new \Exception("Unexpected type for \$extensions: ".WXU::get_type($extensions));
}
}
switch($ext) {
case 'js':
$html[] = WXU::html_tag('script',['src'=>$stats['publicPath'].$p,'charset'=>'utf-8'],'');
break;
case 'css':
$html[] = WXU::html_tag('link',['href'=>$stats['publicPath'].$p,'rel'=>'stylesheet','type'=>'text/css','media'=>$media],null);
break;
}
}
return implode(PHP_EOL, $html);
}
( WP4):
{
apply: function(compiler) {
compiler.plugin('done', function(stats, done) {
let assets = {};
stats.compilation.namedChunks.forEach((chunk, name) => {
assets[name] = chunk.files;
});
fs.writeFile('webpack.stats.json', JSON.stringify({
assetsByChunkName: assets,
publicPath: stats.compilation.outputOptions.publicPath
}), done);
});
}
},
- :
<script src="/assets/runtime~main.a23dfea309e23d13bfcb.js" charset="utf-8"></script>
<link href="/assets/chunk.81da97be08338e4f2807.css" rel="stylesheet" type="text/css"/>
<script src="/assets/chunk.81da97be08338e4f2807.js" charset="utf-8"></script>
<link href="/assets/chunk.b0b8758057b023f28d41.css" rel="stylesheet" type="text/css"/>
<script src="/assets/chunk.b0b8758057b023f28d41.js" charset="utf-8"></script>
<link href="/assets/chunk.00ae08b2c535eb95bb2e.css" rel="stylesheet" type="text/css" media="print"/>
, JS , JS-. .
JS require, . , - , . import() , , . , - , . , .
, . .js, , .css, [chunkhash].
. , , <script>, ... AFAICT:
const fs = require('fs');
class EntryChunksPlugin {
constructor(options) {
this.filename = options.filename;
}
apply(compiler) {
compiler.plugin('done', (stats, done) => {
let assets = {};
for(let chunkGroup of stats.compilation.chunkGroups) {
if(chunkGroup.name) {
let files = [];
for(let chunk of chunkGroup.chunks) {
files.push(...chunk.files);
}
assets[chunkGroup.name] = files;
}
}
fs.writeFile(this.filename, JSON.stringify({
assetsByChunkName: assets,
publicPath: stats.compilation.outputOptions.publicPath
}), done);
});
}
}
module.exports = EntryChunksPlugin;