写在前面
在我的vite专栏里,刚刚实践了一次前端项目优化,其中有个组成部分是cdn引入,后来我发现我的cdn引入是有出入的,特发此文来弥补漏洞;这个出入就是如element-plus
、bootstrap
第三方库在js、css引入后发现我们在vue入口文件的import 'xxxxxxxxxx.css’还是会被打包构建,而且在external的配置方面我们也依靠 vite-plugin-cdn-import
库做到了,但是为什么会打包进去呢?
原因分析
- vite-plugin-cdn-import 配置不到位;
- rollup.js依赖分包配置对所有依赖进行了作用;
实战
带着这俩个疑问,我们开始了摸排,避免不了的就是要看他们的官方文档,因为那里才是最直接获得答案的地方之一;我先是看了vite-plugin-cdn-import;这个包里面并没有什么意外的收获;只是一些简单的参数配置;那我们就转战rollup.js;
我的配置文件如下:
rollupOptions: {
output: {
//静态资源分类打包
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks(id) {
//静态资源分拆打包
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
}
}
}
很显然起分包作用的是下面的函数manualChunks
;那我们本着学习的态度分别解释一下如上参数,本解释来源于翻译软件和个人领悟,如有出入欢迎指正:
- chunkFileNames:用于代码拆分生成共享块时每个块的拆分模式,每个块会按照配置的模式调用函数;属性分为
[format]
:文件格式,如上我们是js,此外还支持.es或.cjs;[hash]
生成的块内容的散列,可以指定特定的hash长度;[name]
:块的名称可通过this.emitFile生成,像如上写法则从内容块中生成; - entryFileNames: 入口文件拆分模式,其参数与chunkFileNames雷同,但有特别之处是如果原生文件不是js,则会参生原始文件格式,如TS、JSX等;
- assetFileNames: 这个就是我们项目src/asset目录下的一些资源在构建输出中我们希望配置的模式,会由每个asset内容来调用次模式,区别与以上俩个属性的地方是extname;资源扩展名,因为我们在丰富的web中会存在如image\audio\mp4\等复杂多样的扩展,这里我们就随着打包去默认配置ext;
- manualChunks():创建自定义共享公共块,参数我直接拿来Type:
{ [chunkAlias: string]: string[] } | ((id: string, {getModuleInfo, getModuleIds}) => string | void)
,参数有俩种可选项,一种是以对象配置manualChunks,{ [chunkAlias: string]: string[] },是已确定的碎片集:
manualChunks: {
lodash: ['lodash']
}
第二种是函数的形参id:
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
}
也可以是:
manualChunks(id, { getModuleInfo }) {
const match = /.*.strings.(\w+).js/.exec(id);
if (match) {
const language = match[1]; // e.g. "en"
const dependentEntryPoints = [];
// we use a Set here so we handle each module at most once. This
// prevents infinite loops in case of circular dependencies
const idsToHandle = new Set(getModuleInfo(id).dynamicImporters);
for (const moduleId of idsToHandle) {
const { isEntry, dynamicImporters, importers } = getModuleInfo(moduleId);
if (isEntry || dynamicImporters.length > 0) dependentEntryPoints.push(moduleId);
// The Set iterator is intelligent enough to iterate over elements that
// are added during iteration
for (const importerId of importers) idsToHandle.add(importerId);
}
// If there is a unique entry, we put it into a chunk based on the entry name
if (dependentEntryPoints.length === 1) {
return `${dependentEntryPoints[0].split('/').slice(-1)[0].split('.')[0]}.strings.${language}`;
}
// For multiple entries, we put it into a "shared" chunk
if (dependentEntryPoints.length > 1) {
return `shared.strings.${language}`;
}
}
}
好了,作者目前的水平还处于初级应用阶段,所以,对于这些函数的应用和解释出自实践感悟,那么我们介绍了这么多,为的就是进一步感受配置,从而实现我们的需求;回到问题2,我们现在怀疑是分包处理了入口的css所以编入了,先从现象上看看我的打包结果,我的cdn已经引好了css,但是入口文件还是有:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xxx</title>
<link href="https://unpkg.com/element-plus@2.2.17/dist/index.css" rel="stylesheet">
<link href="https://unpkg.com/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://unpkg.com/vue@3.2.36/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios@0.27.2/dist/axios.min.js"></script>
<script src="https://unpkg.com/element-plus@2.2.17/dist/index.full.js"></script>
<script src="https://unpkg.com/vue-demi@0.13.11/lib/index.iife.js"></script>
<script src="https://unpkg.com/@element-plus/icons-vue@2.0.9/dist/index.iife.min.js"></script>
<script src="https://unpkg.com/bootstrap@5.2.1/dist/js/bootstrap.js"></script>
<script type="module" crossorigin src="./static/js/index-af90761f.js"></script>
<link rel="modulepreload" crossorigin href="./static/js/js-cookie-1db5286e.js">
<link rel="modulepreload" crossorigin href="./static/js/vue-router-5755d64e.js">
<link rel="modulepreload" crossorigin href="./static/js/pinia-7992cf6b.js">
<link rel="modulepreload" crossorigin href="./static/js/@fortawesome-0742f1fb.js">
<link rel="stylesheet" href="./static/css/index-a80d2be8.css">
<link rel="stylesheet" href="./static/css/element-plus-c08499e6.css"> //多余的
<link rel="stylesheet" href="./static/css/bootstrap-744009a1.css"> //多余的
</head>
<body>
<div id="app"></div>
</body>
</html>
这俩个是多余的,那我们可以看看之前的配置规则打印了什么:
rollupOptions: {
output: {
//静态资源分类打包
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks(id) {
//静态资源分拆打包
// if (id.includes('element-plus') || id.includes('bootstrap')) {
// return false;
// }
console.log(id);
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
}
}
}
看到了吧,这里的id,就是我们的模块依赖情况,if块中的return 就是我们配置共享块的规则,根据这些结果很容易就读出来了;例如:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6aYksJs-1667093573885)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/06f94c821c20436989f70a8d7a4de904~tplv-k3u1fbpfcp-watermark.image?)]
将被拆分,且公共块的规则就是crypto-js;那我们配置if块之外的规则怎么处理的? 实践答案是直接引入;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PoJ7GpVg-1667093573887)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/69f28abe2fa94682bca1b0f1283f3222~tplv-k3u1fbpfcp-watermark.image?)]
我们的需求是cdn引入了,这里应该截断不再引入,经过实践配置规则直接return;就好,更改配置:
rollupOptions: {
output: {
//静态资源分类打包
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks(id) {
//静态资源分拆打包
if (id.includes('element-plus') || id.includes('bootstrap')) {
return;
}
console.log(id);
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
}
}
}
再来看打包文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xxxx</title>
<link href="https://unpkg.com/element-plus@2.2.17/dist/index.css" rel="stylesheet">
<link href="https://unpkg.com/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://unpkg.com/vue@3.2.36/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios@0.27.2/dist/axios.min.js"></script>
<script src="https://unpkg.com/element-plus@2.2.17/dist/index.full.js"></script>
<script src="https://unpkg.com/vue-demi@0.13.11/lib/index.iife.js"></script>
<script src="https://unpkg.com/@element-plus/icons-vue@2.0.9/dist/index.iife.min.js"></script>
<script src="https://unpkg.com/bootstrap@5.2.1/dist/js/bootstrap.js"></script>
<script type="module" crossorigin src="./static/js/index-54d1d6f9.js"></script>
<link rel="modulepreload" crossorigin href="./static/js/js-cookie-1db5286e.js">
<link rel="modulepreload" crossorigin href="./static/js/vue-router-5755d64e.js">
<link rel="modulepreload" crossorigin href="./static/js/pinia-7992cf6b.js">
<link rel="modulepreload" crossorigin href="./static/js/@fortawesome-0742f1fb.js">
<link rel="stylesheet" href="./static/css/index-be96d8dc.css">
//俩项被被产出函数忽略
</head>
<body>
<div id="app"></div>
</body>
</html>
自此我们的需求完成,最大的收获是体验rollupOptions:工作过程,如有偏差还望指教;
最后
📚 vite专栏
☃️ 个人简介:一个喜爱技术的人。
🌞 励志格言: 脚踏实地,虚心学习。
❗如果文章还可以,记得用你可爱的小手点赞👍关注✅,我会在第一时间回关、回访,欢迎进一步交流。
转载:https://blog.csdn.net/g18204746769/article/details/127595489