Vue3项目打包优化

前言

本文介绍在实际项目中进行打包优化过程

目前评分 good

npm install web-vitals

在App.vue加入如下代码测试网页性能指标

import { onLCP, onINP, onCLS, onFCP, onTTFP } from 'web-vitals/attribution'

onCLS(console.log)
onINP(console.log)
onLCP(console.log)
onFCP(console.log)
onTTFB(console.log)

刷新网页,我们可以看到在console出现指标评分如下:
在这里插入图片描述

背景

项目目前的技术栈环境如下:
vite@5.0.10
vue@3.3.13
pinia@2.1.7
ant-design-vue@4.0.8
vue-router@4.2.5

现状分析

优化的主要难点还是从哪里开始去优化,如果不清楚自己的项目问题出现在哪里,就显得比较盲目,不知道优化哪里,那在优化之前我们先分析一下我的文件依赖。

1. 安装插件 rollup-plugin-visualizer

npm install rollup-plugin-visualizer --save-dev

2. 修改vite.config.js

import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig(({ command, mode }) => {
	return {
		plugins: [
			visualizer({
				open: true
			})
		]
	}
})

3. 生成报告

在终端重新运行打包命令

npm run build

打包结束后,会自动打开报告页面如下图所示:
在这里插入图片描述
我们看到占体积较大的是第三方依赖如:z-render (ECharts 底层库 ZRender ), clay-gl ( ECharts -gl 底层库ClayGL), e-chartsecharts-glant-design-vuehighchartsvxe-table。总体积是9.77MB

方案

1. Echarts 按需加载

Echarts 的官方文档我们看到有关按需引入依赖的说明 按需引入Echarts

我们在项目中使用Echarts和Echarts-GL主要是为了绘制3D曲面图,如下图所示:
在这里插入图片描述

1.1 使用 Canvas 或者 SVG 渲染

使用 Canvas 或者 SVG 渲染

如果你是按需引入,则需要手动引入需要的渲染器

import * as echarts from 'echarts/core';
// 可以根据需要选用只用到的渲染器
import { SVGRenderer, CanvasRenderer } from 'echarts/renderers';

echarts.use([SVGRenderer, CanvasRenderer]);

然后,我们就可以在代码中,初始化图表实例时,传入参数 选择渲染器类型:

// 使用 Canvas 渲染器(默认)
var chart = echarts.init(containerDom, null, { renderer: 'canvas' });
// 等价于:
var chart = echarts.init(containerDom);

// 使用 SVG 渲染器
var chart = echarts.init(containerDom, null, { renderer: 'svg' });

1.2 按需引入组件

// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
// 引入标题,提示框,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
  TitleComponent,
  TooltipComponent,
  DatasetComponent,
  TransformComponent,
  VisualComponent
} from 'echarts/components';
// 标签自动布局、全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  DatasetComponent,
  TransformComponent,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer
]);

1.3 按需引入echarts-gl

ECharts-GLECharts 的扩展包,提供 3D 绘图、地球可视化和 WebGL 加速

Echarts-GLGithub 主页我们看到按需引入的指引

import * as echarts from 'echarts/core';
import { SurfaceChart } from 'echarts-gl/charts';
import { Grid3DComponent } from 'echarts-gl/components';

echarts.use([
	SurfaceChart,
	Grid3DComponent
]);

按需引入组件时,有关控件的说明没有在官网文档中给出,需要阅读源码去寻找需要导入的组件。

1.4 总结

本项目按需引入Echarts和Echarts-GL,所作的全部修改如下:

// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core'
// 引入标题,提示框,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
  TitleComponent,
  TooltipComponent,
  DatasetComponent,
  TransformComponent,
  VisualMapComponent
} from 'echarts/components'
// 标签自动布局、全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features'
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers'
// Minimal Import echarts-gl 模块
// import 'echarts-gl'
import { SurfaceChart } from 'echarts-gl/charts'
import { Grid3DComponent } from 'echarts-gl/components'

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  DatasetComponent,
  TransformComponent,
  VisualMapComponent,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer,
  SurfaceChart,
  Grid3DComponent
]);

1.5 效果

重新打包

npm run build

得到report如下:
在这里插入图片描述
我们可以看到打包总体积从9.77MB减小到了8.03MB,减少了1.74MB,减少的值相对于初始值9.77MB减少了17.8%

2. 按需引入 ant-design-vue 组件库

ant-design-vue 默认支持基于 ES modulestree shaking
自动按需引入组件,如果你使用的是 Vite ,我们推荐使用 unplugin-vue-components

2.1 unplugin-vue-components

该插件帮助开发者按需自动导入 Vue 组件

2.1.1 安装
npm install unplugin-vue-components -D

在这里插入图片描述

2.1.2 用法

像平常一样在模板中使用组件,它将按需导入组件,不再需要再导入 (import) 组件或者注册 (register ) 组件。如果您异步注册父组件(或路由懒加载),则自动导入的组件将与其父组件一起进行代码拆分。
它会自动将:

<template>
  <div>
    <HelloWorld msg="Hello Vue 3.0 + Vite" />
  </div>
</template>

<script>
  export default {
    name: 'App',
  }
</script>

转换成:

<template>
  <div>
    <HelloWorld msg="Hello Vue 3.0 + Vite" />
  </div>
</template>

<script>
  import HelloWorld from './src/components/HelloWorld.vue'

  export default {
    name: 'App',
    components: {
      HelloWorld,
    },
  }
</script>

注意: 默认情况下,此插件将导入src/components路径中的组件。您可以使用选项进行自定义dirs

2.1.3 按需导入组件库

认识这个插件真的有种相见恨晚的感觉,它不仅适用于Ant-design-vue,还有其他流行的UI库如Element Plus提供了内置的解析器,以下是它支持的解析器:

  • Ant Design Vue
  • Arco Design Vue
  • BootstrapVue
  • Element Plus
  • Element UI
  • Headless UI
  • IDux
  • Inkline
  • Ionic
  • Naive UI
  • Prime Vue
  • Quasar
  • TDesign
  • Vant
  • Varlet UI
  • VEUI
  • View UI
  • Vuetify — Prefer first-party plugins when possible: v3 + vite, v3 + webpack, v2 + webpack
  • VueUse Components
  • VueUse Directives
  • Dev UI

示例用法:

// vite.config.js
import Components from 'unplugin-vue-components/vite'
import {
  AntDesignVueResolver,
  ElementPlusResolver,
  VantResolver,
} from 'unplugin-vue-components/resolvers'

// your plugin installation
Components({
  resolvers: [
    AntDesignVueResolver(),
    ElementPlusResolver(),
    VantResolver(),
  ],
})
2.1.4 配置项说明
Components({
  // 搜索组件的相对路径
  dirs: ['src/components'],

  // 组件有效的文件扩展名
  extensions: ['vue'],

  // 匹配要检测为组件的文件名的Glob正则表达式
  // 指定该项之后,`dirs` 和`extensions`选项都将被忽略
  // 如果你想要排除已被注册的组件,使用!通配符
  globs: ['src/components/*.{vue}'],

  // 搜索子目录
  deep: true,

  // 自定义组件的解析器
  resolvers: [],

  // 生成 `components.d.ts` 全局申明,也可以是自定义文件名的路径,如果已安装ts,那么默认值是true
  dts: false,

  // 子目录可以作为组件的namespace前缀
  directoryAsNamespace: false,

  // Collapse same prefixes (camel-sensitive) of folders and components
  // to prevent duplication inside namespaced component name.
  // works when `directoryAsNamespace: true`
  collapseSamePrefixes: false,

  // Subdirectory paths for ignoring namespace prefixes.
  // works when `directoryAsNamespace: true`
  globalNamespaces: [],

  // auto import for directives
  // default: `true` for Vue 3, `false` for Vue 2
  // Babel is needed to do the transformation for Vue 2, it's disabled by default for performance concerns.
  // To install Babel, run: `npm install -D @babel/parser`
  directives: true,

  // Transform path before resolving
  importPathTransform: v => v,
  
  // 允许组件覆盖具有相同名称的其他组件
  allowOverrides: false,

  // Filters for transforming targets (components to insert the auto import)
  // Note these are NOT about including/excluding components registered - use `globs` for that
  include: [/\.vue$/, /\.vue\?vue/],
  exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],

  // 项目的vue版本,如未指定,将自动检测
  // 可以接受的值: 2 | 2.7 | 3
  version: 2.7,

  // Only provide types of components in library (registered globally)
  types: []
})

2.2 修改构建配置 vue.config.js

// vite.config.js
import { defineConfig } from 'vite';
import Components from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
export default defineConfig({
  plugins: [
    // ...
    Components({
      resolvers: [
        AntDesignVueResolver({
          importStyle: false, // css in js
        }),
      ],
    }),
  ],
});

2.3 自动转换

然后你可以在代码中直接引入 ant-design-vue 的组件,插件会自动将代码转化为 import { Button } from 'ant-design-vue' 的形式。

import { Button } from 'ant-design-vue';

2.4 效果

重新打包

npm run build

得到report如下:
在这里插入图片描述
我们可以看到打包总体积从8.03MB减小到了6.33MB,减少了1.7MB,减少的量相对于初始值9.77MB,减少了17.4%

3. 按需引入vxe-table

环境

vxe-table@4.6.0
vite@5.0.10

vxe-table 官方文档介绍有关按需加载
的内容,有两种方式,vite-plugin-lazy-importunplugin-vue-components 根据项目的当前环境去选择

方案

1. vite-plugin-lazy-import

如果您使用了 vite,借助插件 vite-plugin-lazy-import 可以实现按需加载模块

1.1 安装
npm install vite-plugin-lazy-import -D
1.2 配置构建工具
// vite.config.js
import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import'

export default defineConfig({
    plugins: [
        // ...,
        lazyImport({
            resolvers: [
                VxeResolver({
                    libraryName: 'vxe-table'
                })
            ]
        })
        // ...
    ]
})
2. unplugin-vue-components

如果您使用了 webpack,借助插件 unplugin-vue-components 可以实现按需加载模块,减少文件体积

2.1 安装
 npm install unplugin-vue-components @vxecli/import-unplugin-vue-components
2.2 配置构建工具
// vue.config.js
import Components from 'unplugin-vue-components/webpack'
import { VxeTableResolver } from '@vxecli/import-unplugin-vue-components'

export default defineConfig({
    plugins: [
        // ...,
        Components({
            resolvers: [
                VxeTableResolver()
            ]
        })
    ]
})
3. 导入使用

以下是全量的组件及模块安装列表:

// ...
import {
    // 全局实例对象
    VXETable,

    // 可选表格模块
    // VxeTableFilterModule,
    // VxeTableEditModule,
    // VxeTableMenuModule,
    // VxeTableExportModule,
    // VxeTableKeyboardModule,
    // VxeTableValidatorModule,
    // VxeTableCustomModule,

    // 可选组件
    VxeIcon,
    VxeTable,
    VxeColumn,
    VxeColgroup,
    // VxeGrid,
    // VxeTooltip,
    // VxeToolbar,
    // VxePager,
    // VxeForm,
    // VxeFormItem,
    // VxeFormGather,
    // VxeCheckbox,
    // VxeCheckboxGroup,
    // VxeRadio,
    // VxeRadioGroup,
    // VxeRadioButton,
    // VxeSwitch,
    // VxeInput,
    // VxeSelect,
    // VxeOptgroup,
    // VxeOption,
    // VxeTextarea,
    // VxeButton,
    // VxeButtonGroup,
    // VxeModal,
    // VxeDrawer,
    // VxeList,
    // VxePulldown
} from 'vxe-table'
// ...

// 导入默认的语言
import zhCN from 'vxe-table/es/locale/lang/zh-CN'

// 导入主题变量,也可以重写主题变量
import 'vxe-table/styles/cssvar.scss'

// 按需加载的方式默认是不带国际化的,自定义国际化需要自行解析占位符 '{0}',例如:
VXETable.setConfig({
    i18n: (key, args) => XEUtils.toFormatString(XEUtils.get(zhCN, key), args)
})

function LazyVxeUITable(app) {
    // 可选表格模块
    // app.use(VxeTableFilterModule)
    // app.use(VxeTableEditModule)
    // app.use(VxeTableMenuModule)
    // app.use(VxeTableExportModule)
    // app.use(VxeTableKeyboardModule)
    // app.use(VxeTableValidatorModule)
    // app.use(VxeTableCustomModule)

    // 可选组件
    app.use(VxeIcon)
    app.use(VxeTable)
    app.use(VxeColumn)
    app.use(VxeColgroup)
    // app.use(VxeVxeGrid)
    // app.use(VxeTooltip)
    // app.use(VxeToolbar)
    // app.use(VxePager)
    // app.use(VxeForm)
    // app.use(VxeFormItem)
    // app.use(VxeFormGather)
    // app.use(VxeCheckbox)
    // app.use(VxeCheckboxGroup)
    // app.use(VxeRadio)
    // app.use(VxeRadioGroup)
    // app.use(VxeRadioButton)
    // app.use(VxeSwitch)
    // app.use(VxeInput)
    // app.use(VxeSelect)
    // app.use(VxeOptgroup)
    // app.use(VxeOption)
    // app.use(VxeTextarea)
    // app.use(VxeButton)
    // app.use(VxeButtonGroup)
    // app.use(VxeModal)
    // app.use(VxeDrawer)
    // app.use(VxeList)
    // app.use(VxePulldown)
}

createApp(App).use(LazyVxeUITable).mount('#app')

采用方案

vite-plugin-lazy-import

安装

在这里插入图片描述

修改vite.config.js
import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import'

export default defineConfig({
    plugins: [
        // ...,
        lazyImport({
            resolvers: [
                VxeResolver({
                    libraryName: 'vxe-table'
                })
            ]
        })
        // ...
    ]
})
组件使用
import {
    // 可选组件
    VxeTable,
    VxeColumn
} from 'vxe-table'
// ...

function LazyVxeUITable(app) {
    // 可选组件
    app.use(VxeTable)
    app.use(VxeColumn)
}

createApp(App).use(LazyVxeUITable).mount('#app')
问题处理

console 有警告消息 Failed to resolve component: vxe-table-custom-panel
在这里插入图片描述
需要引入组件 VxeTableCustomModule 并注册,报错消失

最后改为:

import {
    // 可选组件
    VxeTable,
    VxeColumn,
    VxeTableCustomModule
} from 'vxe-table'
// ...

function LazyVxeUITable(app) {
    // 可选组件
    app.use(VxeTable)
    app.use(VxeColumn)
    app.use(VxeTableCustomModule)
}

createApp(App).use(LazyVxeUITable).mount('#app')

效果

在这里插入图片描述
我们可以看到打包总体积从6.33MB减小到了5.78MB,减少了0.55MB,减少的量相对于初始值9.77MB,减少了5.62%

总结

通过按需加载Echarts, Ant-design-vue和Vxe-table,我们将打包的体积从9.77MB减小到了5.78MB,一共减少了3.99MB,缩小到了初始值的59.16%

代码分割

我们在打包之后,遇到另外一个问题看到终端有一段提示文字:
在这里插入图片描述

(!) Some chunks are larger than 500 KB after minification. Consider:

  • Using dynamic import() to code-split the application
  • Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
  • Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.

build.chunkSizeWarningLimit
类型: number
默认: 500
块大小警告的限制(以 kbs 为单位)

这段提示提示一个vite打包的问题,指的是存在体积过大(大于500KB)的单个js文件,一般调高chunk size就能解决这个问题

解决方案

export default defineConfig({
    plugins: [],
    build: {
        chunkSizeWarningLimit: 1500,
        rollupOptions: {
            output: {
                manualChunks(id) {
                    if (id.includes('node_modules')) {
                        return id.toString().split('node_modules/')[1].split('/')[0].toString();
                    }
                }
            }
        }
    }
})

效果

在这里插入图片描述
我们看到报错信息消失,且体积较大的两个文件也消失了,实际上是被分割成了多块js脚本
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/785168.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

江协科技51单片机学习- p25 无源蜂鸣器

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

C语言 | Leetcode C语言题解之第223题矩形面积

题目&#xff1a; 题解&#xff1a; int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {int area1 (ax2 - ax1) * (ay2 - ay1), area2 (bx2 - bx1) * (by2 - by1);int overlapWidth fmin(ax2, bx2) - fmax(ax1, bx1), overlapHei…

气膜建筑如何在文化旅游行业中应用—轻空间

一、气膜建筑简介 气膜建筑是一种新型建筑形式&#xff0c;其主要结构由高强度膜材、空气支撑系统和固定系统组成。通过不断向膜体内部充气&#xff0c;使其形成稳定的内部压力来支撑整个建筑结构。气膜建筑因其建设速度快、成本相对较低、环保节能等优点&#xff0c;近年来在各…

DDR3 (四)

1 DDR3 8倍预取 DDR3相比DDR2外部IO时钟又提高了一倍&#xff0c;因此DDR3外部IO时钟是内核时钟的4倍&#xff0c;再加上双沿采样&#xff0c;因此DDR3可以实现8倍预取 2 DDR3 芯片位宽 DDR3使用8倍预取技术&#xff0c;指的是芯片位宽&#xff08;DQ数据线位宽&#xff09…

HTML实现图片查看与隐藏

你好呀&#xff0c;我是小邹。 在网页设计中&#xff0c;提供一个直观且用户友好的图片查看功能是提升用户体验的重要一环。本文将详细介绍如何使用HTML、CSS和JavaScript来实现图片的查看与隐藏功能。通过本教程&#xff0c;你将学会如何让页面上的图片在点击时放大显示&…

旋转木马案例

旋转木马 如果接口需要的数据格式和原始数据提供的格式有差异 不要去改接口方法 也不要改原始数据 做一层中间件(数据处理函数/方法) <!DOCTYPE html> <html lang"zh-cn"><head><meta charset"UTF-8"><meta name"viewport…

【机器学习】(基础篇二) —— 监督学习和无监督学习

监督学习和无监督学习 本文介绍机器学习的分类&#xff0c;监督学习和无监督学习 监督学习 监督学习&#xff08;Supervised Learning&#xff09;是机器学习的一个核心分支&#xff0c;大部分的机器学习任务都是由监督学习完成的。 它涉及到使用带有标签的训练数据来训练模…

利用 Python 解析pcap文件

1、问题背景 当面对处理网络数据包分析时&#xff0c;pcap文件作为一个常见的文件格式存储了网络数据包的详细记录&#xff0c;它常常被用来进行网络故障排查或安全分析。为了充分利用这些数据&#xff0c;我们需要对其进行解析并提取出有价值的信息&#xff0c;例如数据包类型…

Why Can’t Robots Click The “I’m Not a Robot” Box On Websites?

Clicking a tiny box tells Google all they need to know about your humanity 你好,我是 Jiabcdefh。 if you’ve browsed the internet for any amount of time, you will likely come across a reCAPTCHA box. These boxes appear when you first enter certain websites…

关于Mars3d的入门

关于Mars3d的入门 一. 创建地球&#xff0c;加载瓦片图层二 矢量图层2.1 常用矢量图层2.1.1 GraphicLayer2.1.2 GeoJsonLayer 2.2 矢量图层的点击事件 三 矢量数据四 事件机制 一. 创建地球&#xff0c;加载瓦片图层 // 1. 创建地球let map new mars3d.Map("mars3dContai…

孕产妇(产科)管理信息系统源码 三甲医院产科电子病历系统成品源代码

孕产妇&#xff08;产科&#xff09;管理信息系统源码 三甲医院产科电子病历系统成品源代码 医院智慧孕产是一种通过信息化手段,实现孕产期宣教、健康服务的院外延伸,对孕产妇健康管理具有重要意义,是医院智慧服务水平和能力的体现。实行涵盖婚前检查、孕期保健、产后康复的一…

极客时间:使用Autogen Builder和本地LLM(Microsoft Phi3模型)在Mac上创建本地AI代理

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

C语言之数据在内存中的存储(1),整形与大小端字节序

目录 前言 一、整形数据在内存中的存储 二、大小端字节序 三、大小端字节序的判断 四、字符型数据在内存中的存储 总结 前言 本文主要讲述整型包括字符型是如何在内存中存储的&#xff0c;涉及到大小端字节序这一概念&#xff0c;还有如何判断大小端&#xff0c;希望对大…

python极速入门笔记(三)

1. 函数 #定义函数""" def 函数名&#xff08;参数&#xff09;:...return ** """ def calc_BMI(weight,height):BMIweight/(height**2)if BMI<18.5:category"偏瘦"elif BMI<25:category"正常"elif BMI<30:catego…

红外光气体检测:1.分子振动与红外吸收、检测系统的基本模型和红外敏感元件

分子振动与红外吸收 分子偶极矩的变化频率与分子内原子振动状态有关&#xff1a;μqd&#xff0c;其中μ是偶极矩&#xff0c;q是电荷&#xff0c;d是正负电荷中心距离。 分子在…

怎样优化 PostgreSQL 中对布尔类型数据的查询?

文章目录 一、索引的合理使用1. 常规 B-tree 索引2. 部分索引 二、查询编写技巧1. 避免不必要的类型转换2. 逻辑表达式的优化 三、表结构设计1. 避免过度细分的布尔列2. 规范化与反规范化 四、数据分布与分区1. 数据分布的考虑2. 表分区 五、数据库参数调整1. 相关配置参数2. 定…

深度学习-梯度下降算法-NLP(五)

梯度下降算法 深度学习中梯度下降算法简介找极小值问题数学上求最小值梯度梯度下降算法 找极小值问题在深度学习流程中深度学习整体流程图求解损失函数的目标权重的更新 深度学习中梯度下降算法简介 找极小值问题 引子&#xff1a; 我们训练一个人工智能模型&#xff0c;简单…

记录一次Nginx的使用过程

一、Docker安装配置nginx 1.拉取镜像 docker pull nginx2.创建挂载目录 启动前需要先创建Nginx外部挂载目录文件夹 主要有三个目录 conf&#xff1a;配置文件目录log&#xff1a;日志文件目录html&#xff1a;项目文件目录&#xff08;这里可以存放web文件&#xff09; 创建挂…

【沐风老师】3DMAX建筑体块生成插件BuildingBlocks使用方法详解

BuildingBlocks建筑体块生成插件使用方法详解 听说你还在手动建配景楼&#xff1f;有了BuildingBlocks这个插件&#xff0c;一分钟搞定喔&#xff01; 3DMAX建筑体块生成插件BuildingBlocks&#xff0c;用于快速自定义街道及生成配景楼区块。 【适用版本】 3dMax2019及更高版…