一、项目使用本地图片打包后不显示
1、在html中时候,本地运行和打包后线上运行都ok。
<img src="@/assets/logo.png" >
2、用动态数据,本地运行ok,打包后线上运行不显示
let list=[ "/src/assets/logo.png", "/src/assets/logo.png", ] // 这个地方的数据如果不用/src,那么本地直接报错。 // 如果是vue3+webpack可以使用require引入,但vite没有require <div v-for="item in list" :key="item"> <img :src="item" > </div>
3、适用于处理单个链接的资源文件
import homeIcon from '@/assets/images/home/home_icon.png' <img :src="homeIcon" />
4、用动态数据且本地和线上访问都可显示
import.meta.url 是一个 ESM 的原生功能,会暴露当前模块的 URL。将它与原生的 URL 构造器 组合使用,在一个 JavaScript 模块中,通过相对路径我们就能得到一个被完整解析的静态资源 URL:
let list=[ new URL("@/assets/logo.png", import.meta.url).href, new URL("@/assets/logo.png", import.meta.url).href, ] <div v-for="item in list" :key="item"> <img :src="item" > </div>
二、使用插件vite-plugin-zip-pack打包dist文件到zip
开发过程中一个经常做的事就是将 ./dist 文件夹打包成 zip 分发。
每次手动打包还是很费劲的, vite 同样也有能把 ./dist 文件夹打包成 .zip 的插件,当然这个打包的文件夹不一定非得是 ./dist,可以是任何位置,只要指定好就可以了。
1、安装 vite 插件
npm i -D vite-plugin-zip-pack
2、配置插件
vite.config.js
import zipPack from "vite-plugin-zip-pack" export default defineConfig({ plugins: [ vue(), zipPack({ inDir: 'dist',//要打包的文件夹 outDir: 'dist',//打包好的 zip 文件放到哪个文件夹下 outFileName: `dist.zip`,// 打包好的文件名 pathPrefix: '' }), ], })
这个 .zip 文件中的内容是不带 ./dist 这个外置文件夹的,直接就是 ./dist 里面的内容。
也就是说,解压后,没有 dist 这一层文件夹,使用的时候要注意。
三、打包配置vite.config.js
1、打包结构控制
vite.config.js
export default defineConfig({ build:{ rollupOptions:{ output: { // entry部分的文件命名,我们这里是spa,所以entry写死也没事,多入口的话需要注意了 entryFileNames: "assets/js/[name]-[hash].js", // 自定义chunk如何命名法,包含懒加载或者自定义分包的一些内容的命名 chunkFileNames: "assets/js/[name]-[hash].js", // 除js之外其他资源的存放 assetFileNames: "assets/[ext]/[name]-[hash].[ext]", // 这里注意一下中括号里面的东西都是占位符 } } } })
2、手动分包,提取第三方库单独打包
vite.config.js
export default defineConfig({ build:{ rollupOptions:{ // 我们这里测试一下,将vue全家桶放在一个公共chunk之中 manualChunks:{ vueall:["vue","vue-router","vuex"] } } } })
或者
export default defineConfig({ build:{ rollupOptions:{ manualChunks(id) { if (id.includes('vant') || id.includes('vue-router')) { return 'vendor'; } if (id.includes('node_modules')) { return 'dependencies'; } }, } } })
3、全部常用配置
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // https://vitejs.dev/config/ export default defineConfig({ // 插件部分 plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }), ], //构建部分,该部分涉及到打包的相关内容 build:{ // target指的是js的兼容版本,默认是['es2020', 'edge88', 'firefox78', 'chrome87', 'safari14'] // 相关值可以是一个es版本(最低支持es2015),或者相关的流浪器版本 // 该部分任务由esbuild完成 target:"es2015", // 打包之后的文件放的文件夹,该部分其实根据项目不一样是不一样的 outDir:"dist", //内联资源限制,图片等资源的请求需要http请求,小于该值的资源可以直接转成base64之后,默认是4kb assetsInlineLimit:4096, //懒加载组件之中的css分离,默认是true,css内联到对应的组件中,false的话项目中用到的css全放到一个css文件中 cssCodeSplit:true, // cssTarget该熟悉是针对非主流浏览器使用,给css添加一个转换目标,类似target属性 // cssMinify css的最小化压缩方式,我不是很懂,但应该和合并同类项类似 // sourcemap:true是否储存sourcemap文件,这个文件记载着js源码和打包后代码的位置关系,方便定位出错,我暂时不知道有什么用 // chunkSizeWarningLimitchunk大小限制,会和未压缩之前的chunk大小进行比较,有chunk超过这个值会报警,默认500kb // assetsDir静态资源的存放位置,默认是assets,注意这个静态资源包含了除js之外的其他内容 assetsDir:"assets", // rollupOptions // vite使用rollup实现打包,这就是写具体配置的地方,为父没用过,先看一下 rollupOptions:{ // input不写其实啥事都没有,写的话,spa单页面必须注意要把html页面写进去否则不产生html页面 // input:["./src/main.js",'./index.html'], // 出口,这里就涉及比较多的内容 output:{ // entry部分的文件命名,我们这里是spa,所以entry写死也没事,多入口的话需要注意了 entryFileNames: "assets/js/[name]-[hash].js", // 自定义chunk如何命名法,包含懒加载或者自定义分包的一些内容的命名 chunkFileNames: "assets/js/[name]-[hash].js", // 除js之外其他资源的存放 assetFileNames: "assets/[ext]/[name]-[hash].[ext]", // 这里注意一下中括号里面的东西都是占位符 // compact用于压缩rollup产生的临时代码 compact: true, // 其他的一些内容 // external哪些模块被排除在打包之外,我感觉cdn的引入应该挺需要使用这个 // manualChunks自定义公共chunk,在多入口的时候很有用 // 我们这里测试一下,将vue全家桶放在一个公共chunk之中 manualChunks:{ vueall:["vue","vue-router","vuex"] } }, // 设置为true之后,后续打包的时候只对更改的模块重新分析,加快打包速度 cache:true } } })
四、使用 reactive 声明数组,请求接口数据赋值后不响应
1、将接口请求到的列表数据赋值后不响应
const tableData = reactive([]); const getData = () => { const res = [{userId: 1},{userId: 2},{userId: 3},{userId: 4}]; //假设请求接口返回的数据 // 方法1 失败,直接赋值丢失了响应性 tableData = res; // 方法2 这样也是失败 tableData.concat(res); };
2、原因分析
- vue3使用proxy,对于对象和数组都不能直接整个赋值。reactive声明的响应式对象被 arr 代理,操作代理对象需要有代理对象的前缀,直接覆盖会丢失响应式。
- 只有push或者根据索引遍历赋值才可以保留reactive数组的响应性。
3、解决方案
- 方案1,定义数组时,使用数组的push方法
const tableData = reactive([]); const getData = () => { const res = [{userId: 1},{userId: 2},{userId: 3},{userId: 4}]; //假设请求接口返回的数据 res.forEach(item => { tableData.push(item); }); };
- 方案2,定义数组时,使用数组的push方法
const tableData = reactive([]) const getData = () => { const res = [{userId: 1},{userId: 2},{userId: 3},{userId: 4}]; //假设请求接口返回的数据 tableData.push(...res); };
- 方案3,定义数组时,需要在外面包一层
const tableData = reactive({ listData:[] }) const getData = () => { const res = [{userId: 1},{userId: 2},{userId: 3},{userId: 4}]; //假设请求接口返回的数据 tableData.listData = res; };
- 方案4,定义对象时,使用Object.assign赋值
const person = reactive({name:'张三',age:18}) const getData = () => { const res = {name:'李四',age:20}; //假设请求接口返回的数据 Object.assign(person ,res) };
- 方案5,定义简单对象时,使用ref替换reactive
const person = ref({name:'张三',age:18}) const getData = () => { const res = {name:'李四',age:20}; //假设请求接口返回的数据 person.value = res };