vite官网搭建工程指南: https://vitejs.dev/guide/#scaffolding-your-first-vite-project
使用自选配置去构建vite项目:
yarn create vite
构建一些具备框架功能的预设模板(不需要你自选配置)
yarn create vite my-react-ts-app --template react-ts # 还有更多配置可以参阅官网
vuex, vue-router,
路径补全
before:
import _ from "lodash"; // lodash可能也import了其他的东西
after:
import __vite__cjsImport0_lodash from "/node_modules/.vite/deps/lodash.js?v=ebe57916";
1.在处理的过程中如果说看到了有非绝对路径或者相对路径的引用, 他则会尝试开启路径补全
2.找寻依赖的过程是自当前目录依次向上查找的过程, 直到搜寻到电脑根目录如:C盘,搜寻到对应依赖为止 /user/node_modules/lodash, ../
依赖预构建
// 做了什么
1.vite会找到对应的依赖
2.调用esbuild(对js语法进行处理的一个库), 将其他规范的代码转换成esmodule规范,
3.放到当前目录下的node_modules/.vite/deps, 同时对esmodule规范的各个模块进行统一集成
// 解决问题
1.不同的第三方包会有不同的导出格式(这个是vite没法约束人家的事情)
2.对路径的处理上可以直接使用.vite/deps, 方便路径重写
3.叫做网络多包传输的性能问题(也是原生esmodule规范不敢支持node_modules的原因之一), 有了依赖预构建以后无论他有多少的额外export 和import, vite都会尽可能的将他们进行集成最后只生成一个或者几个模块
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
//策略模式
const envResolver = {
"build": ()=>Object.assign({}, baseConfig, 生产环境的vite配置),
"serve": ()=>Object.assign({}, baseConfig,开发环境的vite配置)
}
// https://vitejs.dev/config/
export default defineConfig(({command:"build" | "serve"})=>{
return envResolver[command]();
})
环境变量: 会根据当前的代码环境产生值的变化的变量就叫做环境变量
1.vite内置了dotenv这个第三方库
2.dotenv会自动读取.env文件
3.解析这个文件中的对应环境变量 并将其注入到process.env对象下(但是vite考虑到和其他配置的
一些冲突问题, 它不会直接注入到process对象下)
//1.创建文件
.env: 所有环境都需要用到的环境变量
.env.development: 开发环境需要用到的环境变量(默认情况下vite将我们的开发环境取名为development)
.env.production: 生产环境需要用到的环境变量(默认情况下vite将我们的生产环境取名为production)
//2.文件定义内容格式(注意:默认必须VITE_开头)
VITE_JIRONGLIANG = 你好
//如果想要自定义环境变量开头需要在配置项中添加envPrefix属性
export default defineConfig({
envPrefix: "ENV_"
})
ENV_JIRONGLIANG = 你好
//客户端
1.在客户端使用(也就是vue文件中)vite会将对应的环境变量注入到import.meta.env里去
console.log(import.meta.env)
//服务端
1.在服务端使用(具体一点就是配置文件中)loadEnv方法
// 第一个参数是.env.xxxx名字相匹配 确认是那个文件
// 如:yarn dev --mode devlop
// 就是匹配.env.devlop文件
// 第二个参数不是必须要使用process.cwd(), 是当前env所在的目录路径
// 第三个参数是.env文件名 默认就是.env
export default defineConfig(({command,mode})=>{
//console.log(command,"区分环境运行的命令")
//console.log(mode,"细分的环境可自定义")
const env = loadEnv(mode, process.cwd(), "");
return {
plugins:[vue()]
}
})
vite天生就支持css文件的直接处理
webpack需要安装并配置
css-loader
和style-loader | mini-css-extract-plugin
,处理 css 文件
- vite在读取到main.js中引用到了Index.css
- 直接去使用fs模块去读取index.css中文件内容
- 直接创建一个style标签, 将index.css中文件内容直接copy进style标签里
- 将style标签插入到index.html的head中
- 将该css文件中的内容直接替换为js脚本(方便热更新或者css模块化), 同时设置Content-Type为js 从而让浏览器以JS脚本的形式来执行该css后缀的文件
- module.css (module是一种约定, 表示需要开启css模块化)
- 他会将你的所有类名进行一定规则的替换(将footer 替换成 _footer_i22st_1)
- 同时创建一个映射对象{ footer: “_footer_i22st_1” }
- 将替换过后的内容塞进style标签里然后放入到head标签中 (能够读到index.html的文件内容)
- 将componentA.module.css内容进行全部抹除, 替换成JS脚本
- 将创建的映射对象在脚本中进行默认导出
/**创建*/
1.创建一个compoment.module.css文件写入样式
.footer {
width: 200px;
height: 200px;
background-color: beige;
}
.footer-content {
width: 200px;
height: 200px;
background-color: var(--globalColor);
}
//使用
import componentCss from "./componentA.module.css";
const div = document.createElement("div");
document.body.appendChild(div);
div.className = componentCss.footerContent;
在vite.config.js中我们通过css属性去控制正个vite对于css的处理行
localConvention: "camelCaseOnly"修改生成的配置对象的key的展示形式(驼峰还是中划线形式)
export default defineConfig({
css: {
modules: {
localsConvention: "camelCaseOnly",
}
}
})
scopeBehaviour:“local” 配置当前的模块化行为是模块化还是全局化global | local (模块化加hash 全局化就是不改变类名)
export default defineConfig({
css: {
modules: {
scopeBehaviour: "local",
}
}
})
generateScopedName:"[name][local][hash:5]"生成的类名的规则 (配置成字符串规则: https://github.com/webpack/loader-utils#interpolatename)
export default defineConfig({
css: {
modules: {
generateScopedName: (name, filename, css) => {
// name -> 代表的是你此刻css文件中的类名
// filename -> 是你当前css文件的绝对路径
// css -> 给的就是你当前样式
console.log("name", name, "filename", filename, "css", css); // 这一行会输出在哪??? 输出在node
// 配置成函数以后, 返回值就决定了他最终显示的类型
return `${name}_${Math.random().toString(36).substr(3, 8) }`;
}
}
}
})
hashPrefix:“Hello”, 你配置的这个字符串会参与到最终的hash生成, (hash: 只要你的字符串有一个字不一样, 那么生成的hash就完全不一样, 但是只要你的字符串完全一样, 生成的hash就会一样)
export default defineConfig({
css: {
modules: {
hashPrefix: "hello"
}
}
})
globalModulePaths:[“./componentB.module.css”]代表你不想参与到css模块化的路径
export default defineConfig({
css: {
modules: {
globalModulePaths: ["./componentB.module.css"]
}
}
})
相关less的配置Less 教程_Less 中文网 (lesscss.com.cn)
export default defineConfig({
css: {
preprocessorOptions: { // key + config key代表预处理器的名
less: { // 整个的配置对象都会最终给到less的执行参数(全局参数)中去
// 在webpack里就给less-loader去配置就好了
math: "always",
globalVars: { // 全局变量
mainColor: "red",
}
},
},
devSourcemap: true,
}
})
vite天生对postcss有非常良好的支持
PostCss是后处理器就像babel对css代码进行降级和兼容
需要下载不同的Plugins支持不同的功能
安装依赖
postcss-preset-env 包含了 必要的其他依赖
yarn add postcss-preset-env -D
创建配置文件文件 ( postcss.config.js )
所需的Plugins
const postcssPresetEnv = require('postcss-preset-env');
// postcssPresetEnv一次吧必要的插件都装上
module.exports = {
plugins: [
postcssPresetEnv(/* pluginOptions */)
],
}
1.对高语法进行降级如
/** before */
.content {
width: 800px;
.main {
width: clamp(100px, 30%, 200px);
user-select: none; // 他在其他浏览器上不支持
}
}
/** after */
.content {
width: 800px;
.main {
width: max(100px, min(30%, 200px));
-webkit-user-select: none;
-moz-user-select: none;
user-select: non
}
}
import postcssPresetEnv from 'postcss-preset-env';
export default defineConfig({
css: {
postcss: {
plugins: [
postcssPresetEnv({})
],
}
}
})
- 如果是vite+vue3 则 用postcss.config.js文件会报错
// 解决方案
postcss.config.cjs
- 全局变量问题
import postcssPresetEnv from 'postcss-preset-env';
// const path = require("path"); // 做路径处理的 node用的其实是commonjs标准
import path from "path"; // 做路径处理的 vite只能用 esmodule 标准
export default defineConfig({
css: {
postcss: {
plugins: [
postcssPresetEnv({
importFrom: path.resolve(__dirname, "./variable.css"), // 就好比你现在让postcss去知道 有一些全局变量他需要记下来
})
],
}
}
})
variable.css文件
/* 我们使用的一些未来的css特性是不需要经过less sass的预处理器进行编译, 我们只用交给postcss去处理 */
:root {
--globalColor: lightblue;
}
// 加载静态图片资源
import sylasPicUrl from "@assets/images/sylas.png";
console.log("sylasPicUrl", sylasPicUrl);
const img = document.createElement("img");
img.src = sylasPicUrl;
document.body.append(img);
如果你用的不是vite, 在其他的一些构建工具里 json文件的导入会作为一个JSON字符串形式存在
尽量使用解构方便摇树优化
import { name } from "./src/assets/json/index.json";
console.log("jsonFile", name);
1.raw
服务端 他会去读取这个图片文件的内容 —> Buffer 二进制的字符串
2.url
服务端返回图片路径 默认就是url
// 加载静态图片资源
import sylasPicUrl from "@assets/images/sylas.png?raw";
const img = document.createElement("img");
img.src = sylasPicUrl;
document.body.append(img);
import { defineConfig } from "vite";
import path from "path";
export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"), // 设置别名, 以后我们在其他组件中可以使用@来代替src这个目录
}
}
})
#二、webpack处理图片和字体
处理代码中引入的图片文件、字体文件
css-loader
处理:css 代码中 url()
引入的图片或字体资源模块
处理:js 代码中 import
引入的图片或字体css-loader
的项目,找一些图片放入 src/assets/images/
目录 <div class="my-img">div>
<style>
.my-img {
width: 200px;
height: 200px;
background: url('./images/pic1.png') center center no-repeat;
background-size: contain;
}
style>
dist
,并自动生成了随机文件名以上功能都是由 css-loader
完成的,它可以处理通过 url()
引用的资源
index.html
中添加元素<img id="img2" src="" width="200" height="200" />
<script>
// 导入一张图片
import pic2 from './assets/images/pic2.png'
// 将导入的图片设置到 img 标签上
const img2 = document.getElementById('img2')
img2.src = pic2
script>
import
导入的资源文件,需使用 webpack 内置的特殊 loader:Asset Modules在 webpack.config.js
中添加规则:
// 通过 Asset Modules 处理以下后缀名的图片或字体文件
{
test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
type: "asset"
}
【Asset Moduls 的说明】
它其实是 webpack 内置的一种专用于处理静态资源的 loader。
type
属性可设置为下列值:
asset/resource
将资源处理成单独文件,并得到它的 URL 路径asset/inline
将资源处理成 data URI 字符串asset/source
将资源处理成它的原始内容asset
根据文件大小,在处理成 data URI 字符串和单独文件之间自动选择
vite-aliases可以帮助我们自动生成别名
Install
npm i vite-aliases -D
Add it to vite.config.js
// vite.config.js
import { ViteAliases } from 'vite-aliases'
export default {
plugins: [
ViteAliases()
]
};
插件就是在不同生命周期做不同的事
在 config()生命周期中 添加alias别名
// vite的插件必须返回给vite一个配置对象
const fs = require("fs");
const path = require("path");
function diffDirAndFile(dirFilesArr = [], basePath = "") {
const result = {
dirs: [],
files: []
}
dirFilesArr.forEach(name => {
// 我直接用异步的方式去写的
const currentFileStat = fs.statSync(path.resolve(__dirname, basePath + "/" + name));
console.log("current file stat", name, currentFileStat.isDirectory());
const isDirectory = currentFileStat.isDirectory();
if (isDirectory) {
result.dirs.push(name);
} else {
result.files.push(name);
}
})
return result;
}
function getTotalSrcDir(keyName) {
const result = fs.readdirSync(path.resolve(__dirname, "../src"));
const diffResult = diffDirAndFile(result, "../src");
console.log("diffResult", diffResult);
const resolveAliasesObj = {}; // 放的就是一个一个的别名配置 @assets: xxx
diffResult.dirs.forEach(dirName => {
const key = `${keyName}${dirName}`;
const absPath = path.resolve(__dirname, "../src" + "/" + dirName);
resolveAliasesObj[key] = absPath;
})
return resolveAliasesObj;
}
module.exports = ({
keyName = "@"
} = {}) => {
return {
config(config, env) {
// 只是传给你 有没有执行配置文件: 没有
console.log("config", config, env);
// config: 目前的一个配置对象
// production development serve build yarn dev yarn build
// env: mode: string, command: string
// config函数可以返回一个对象, 这个对象是部分的viteconfig配置【其实就是你想改的那一部分】
const resolveAliasesObj = getTotalSrcDir(keyName);
console.log("resolve", resolveAliasesObj);
return {
// 在这我们要返回一个resolve出去, 将src目录下的所有文件夹进行别名控制
// 读目录
resolve: {
alias: resolveAliasesObj
}
};
}
}
}
帮我们动态的去控制整个html文件中内容
<%= title %>
在index.html中ejs在服务端会用的比较频繁 因为服务端可能经常会动态的去修改index.html的内容
npm i vite-plugin-html -D
import { createHtmlPlugin } from 'vite-plugin-html'
export default defineConfig({
plugins: [
createHtmlPlugin({
inject: {
data: {
title:"首页"
}
}
})
]
})
module.exports = (options) => {
return {
// 转换html的
// 将我们插件的一个执行时机提前
transformIndexHtml: {
enforce: "pre",
transform: (html, ctx) => {
// ctx 表示当前整个请求的一个执行期上下文: api /index.html /user/userlist json get post headers
console.log("html", html);
return html.replace(/<%= title %>/g, options.inject.data.title);
}
}
}
}
模拟后端数据方便开发
npm i mockjs -S npm i vite-plugin-mock -D
import { viteMockServe } from 'vite-plugin-mock'
export default ({ command }: ConfigEnv): UserConfigExport => {
return {
plugins: [
viteMockServe({
mockPath: 'mock',
localEnabled: command === 'serve',
}),
],
}
}
创建模拟后端数据 mock.js
const mockJS = require("mockjs");
const userList = mockJS.mock({
"data|100": [{
name: "@cname", // 表示生成不同的中文名
// ename: mockJS.Random.name(), // 生成不同的英文名
"id|+1": 1, //
time: "@time",
date: "@date"
}]
})
module.exports = [
{
method: "post",
url: "/api/users",
response: ({ body }) => {
// body -> 请求体
// page pageSize body
return {
code: 200,
msg: "success",
data: userList
};
}
},
]
模块联邦主要用于微前端的架构体系中, 他允许你在两个不同的项目中采用公用模块以及进行模块复用
项目A
// project a webpack config
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "module", // 你要暴露出去的公用模块的名称
filename: "module-entry.js", // 你暴露出去的公用模块最终会打包到一个js文件里, 你可以配置这个js文件名
exposes: {
// 具体暴露的模块
"./cloneDeep": "./src/cloneDeep.js"
}
})
]
}
项目B
// project b webpack config
module.exports = {
plugins: [
new ModuleFederationPlugin({
remotes: {
moduleA: "module@http:localhost:8080/cloneDeep.js", // 就引入了, 然后导入的时候直接module/cloneDeep就好了
}
})
]
}
vite-aliases可以帮助我们自动生成别名
Install
npm i vite-aliases -D
Add it to vite.config.js
// vite.config.js
import { ViteAliases } from 'vite-aliases'
export default {
plugins: [
ViteAliases()
]
};
插件就是在不同生命周期做不同的事
在 config()生命周期中 添加alias别名
// vite的插件必须返回给vite一个配置对象
const fs = require("fs");
const path = require("path");
function diffDirAndFile(dirFilesArr = [], basePath = "") {
const result = {
dirs: [],
files: []
}
dirFilesArr.forEach(name => {
// 我直接用异步的方式去写的
const currentFileStat = fs.statSync(path.resolve(__dirname, basePath + "/" + name));
console.log("current file stat", name, currentFileStat.isDirectory());
const isDirectory = currentFileStat.isDirectory();
if (isDirectory) {
result.dirs.push(name);
} else {
result.files.push(name);
}
})
return result;
}
function getTotalSrcDir(keyName) {
const result = fs.readdirSync(path.resolve(__dirname, "../src"));
const diffResult = diffDirAndFile(result, "../src");
console.log("diffResult", diffResult);
const resolveAliasesObj = {}; // 放的就是一个一个的别名配置 @assets: xxx
diffResult.dirs.forEach(dirName => {
const key = `${keyName}${dirName}`;
const absPath = path.resolve(__dirname, "../src" + "/" + dirName);
resolveAliasesObj[key] = absPath;
})
return resolveAliasesObj;
}
module.exports = ({
keyName = "@"
} = {}) => {
return {
config(config, env) {
// 只是传给你 有没有执行配置文件: 没有
console.log("config", config, env);
// config: 目前的一个配置对象
// production development serve build yarn dev yarn build
// env: mode: string, command: string
// config函数可以返回一个对象, 这个对象是部分的viteconfig配置【其实就是你想改的那一部分】
const resolveAliasesObj = getTotalSrcDir(keyName);
console.log("resolve", resolveAliasesObj);
return {
// 在这我们要返回一个resolve出去, 将src目录下的所有文件夹进行别名控制
// 读目录
resolve: {
alias: resolveAliasesObj
}
};
}
}
}
帮我们动态的去控制整个html文件中内容
<%= title %>
在index.html中ejs在服务端会用的比较频繁 因为服务端可能经常会动态的去修改index.html的内容
npm i vite-plugin-html -D
import { createHtmlPlugin } from 'vite-plugin-html'
export default defineConfig({
plugins: [
createHtmlPlugin({
inject: {
data: {
title:"首页"
}
}
})
]
})
module.exports = (options) => {
return {
// 转换html的
// 将我们插件的一个执行时机提前
transformIndexHtml: {
enforce: "pre",
transform: (html, ctx) => {
// ctx 表示当前整个请求的一个执行期上下文: api /index.html /user/userlist json get post headers
console.log("html", html);
return html.replace(/<%= title %>/g, options.inject.data.title);
}
}
}
}
模拟后端数据方便开发
npm i mockjs -S npm i vite-plugin-mock -D
import { viteMockServe } from 'vite-plugin-mock'
export default ({ command }: ConfigEnv): UserConfigExport => {
return {
plugins: [
viteMockServe({
mockPath: 'mock',
localEnabled: command === 'serve',
}),
],
}
}
创建模拟后端数据 mock.js
const mockJS = require("mockjs");
const userList = mockJS.mock({
"data|100": [{
name: "@cname", // 表示生成不同的中文名
// ename: mockJS.Random.name(), // 生成不同的英文名
"id|+1": 1, //
time: "@time",
date: "@date"
}]
})
module.exports = [
{
method: "post",
url: "/api/users",
response: ({ body }) => {
// body -> 请求体
// page pageSize body
return {
code: 200,
msg: "success",
data: userList
};
}
},
]
模块联邦主要用于微前端的架构体系中, 他允许你在两个不同的项目中采用公用模块以及进行模块复用
项目A
// project a webpack config
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "module", // 你要暴露出去的公用模块的名称
filename: "module-entry.js", // 你暴露出去的公用模块最终会打包到一个js文件里, 你可以配置这个js文件名
exposes: {
// 具体暴露的模块
"./cloneDeep": "./src/cloneDeep.js"
}
})
]
}
项目B
// project b webpack config
module.exports = {
plugins: [
new ModuleFederationPlugin({
remotes: {
moduleA: "module@http:localhost:8080/cloneDeep.js", // 就引入了, 然后导入的时候直接module/cloneDeep就好了
}
})
]
}
强缓存:服务端会给响应头中添加expires设置过期时间 在这个时间内是不会重新请求而是从缓存中取
协商缓存:是否使用缓存要和后端商量一下,当服务端打上协商缓存的标记后,下次发请求时会发协商请求给服务端如果不需要就返回304拿缓存
组件是会频繁的挂载和卸载:如果我们在某个组件中有定时器,不清除下次挂载等于开启两个线程
// react hook
const [timer,setTimer] = useState(null);
useEffect(()=>{
setTimer(setTimeout(()=>{
return () => cleatTimeout(timer)
}))
})
// 对作用域的一个控制
const arr = [1 ,2]
// 由近到远
for(let i= 0 , len=arr.length;i<=len;i ++){
}
传统的javascript 动画是通过定时器 setTimeout 或者 setInterval 实现的。但是定时器动画一直存在两个问题
- 动画的循时间环间隔不好确定,设置长了动画显得不够平滑流畅,设置短了浏览器的重绘频率会达到瓶颈,推荐的最佳循环间隔是16.7ms(大多数电脑的显示器刷新频率是60Hz,1000ms/60)
- 定时器第二个时间参数只是指定了多久后将动画任务添加到浏览器的UI线程队列中,如果UI线程处于忙碌状态,那么动画不会立刻执行。为了解决这些问题,H5 中加入了 requestAnimationFrame以及requestIdleCallback
- 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
- 在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的 CPU、GPU 和内存使用量
- requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了 CPU 开销requestAnimationFrame的回调会在每一帧确定执行,属于高优先级任务
let myReq;
let i = 0;
function step(timestamp) {
console.log(i++);
myReq = window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
document.onclick = function(){
window.cancelAnimationFrame(myReq); // 专属清除方式
}
为了在渲染空闲时间执行优先级不高的操作,以避免阻塞渲染。
当前帧的运行时间小于刷新频率(16.6ms),函数fn才会执行。否则,就推迟到下一帧,以此类推。如果timeout时间内都没有时间,fn则会强制执行。
// 函数fn接受deadline对象作为参数,deadline对象有两个属性:timeRemaining和didTimeout。
// timeRemaining() 返回当前帧还剩余的毫秒数。
// didTimeout 指定的时间是否过期。
function lowWork(deadline) {
while (
(deadline.timeRemaining() > 0 || deadline.didTimeout) &&
taskList.length > 0
) {
doWork();
}
if (taskList.length > 0) {
requestIdleCallback(lowWork);
}
}
requestIdleCallback(lowWork, 2000);
尽量避免太过于深的css嵌套
关注继承属性: 能继承就不要重复写
优化体积
压缩 treeshaking 图片资源压缩 cdn加载 分包 …
名字没有变化,那么他就不会重新去拿
hash: 只要有内容变化hash就会变 文件名不一样就会重新请求
分包就是吧不容易改变的文件,进行单独的打包处理
创建新目录,编写以下文件
公共模块:src/common/index.ts
import { cloneDeep } from 'lodash'
cloneDeep([])
页面入口1:src/index.ts
import { forEach } from 'lodash'
import './common/index'
const mainArr = []
forEach(mainArr, el => {
window.console.log(el)
})
页面入口2:src/product.ts
import { forEach } from 'lodash'
import './common/index'
const mainArr = []
forEach(mainArr, () => {
window.console.log('12')
})
配置 vite
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig(() => {
return {
build: {
minify: false,
rollupOptions: {
input: {
main: path.resolve(__dirname, './index.html'),
product: path.resolve(__dirname, './product.html')
},
output: {
manualChunks: (id: string) => {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
}
})
打包并观察结果 自己试试
npm i vite-plugin-compression -D
// 静态资源压缩
import viteCompression from 'vite-plugin-compression';
export default defineConfig({
plugins: [
viteCompression({
verbose: true,
disable: false, // 不禁用压缩
deleteOriginFile: false, // 压缩后是否删除原文件
threshold: 10240, // 压缩前最小文件大小
algorithm: 'gzip', // 压缩算法
ext: '.gz' // 文件类型
})
],
});
> webpack: 是将所有的文件打包之后才会构建开发服务器
>
> vite: 是直接将入口文件 index.html 抛出去 如果引用了main.js 通过浏览器 esmodule的规范 去请求开发服务器 所以 vite是按需加载的
按需加载和动态导入有异曲同工之妙
动态导入是es6的新特性在此之前webpack也有自己的import()实现 使用动态导入按需加载
在路由文件中
import("@/component/index.vue") //返回的是一个promise
function import (path){
return new Promise((resolv)=>{
// vite 用的是es原生的动态导入 是浏览器自己执行的
//e函数创建了promise.all 创建了一个script标签 src只想home这个文件
webpack__require.e().then(() =>{
const result = await webpack__require(path)
})
})
}
当没有进入过某个页面中把这个组件放入script标签里面去 但是布塞茹body里面
当进入这个页面才添加到body
cdn:content delivery network 内容分发网络
将包用连接的形式加入到项目里
具体步骤
yarn add vite-plugin-cdn-import -D
import importToCDN from 'vite-plugin-cdn-import'
export default defineConfig({
plugins: [
importToCDN({
name: 'lodash',
var: '_',
path: `umd/react-dom.production.min.js`,
})
],
});
对应
import _ from "lodash"; name 和 var