基于vite实现基本的浏览器兼容解决方案

浏览器兼容性解决方案

首先推荐一个网站,可以用来查看浏览器的兼容情况:caniuse.com/

一、JS兼容


推荐使用legacy

推荐原因:为打包后的文件提供传统浏览器兼容性支持 (不支持esm的浏览器),同时还有语法降级处理

缺点:打包时间较长

注意: vite4的legacy插件最高目前是4.1.1,再高的版本只支持vite5了,这里以vite5为例。

集成
1、安装依赖

使用npm

css 复制代码
npm i @vitejs/plugin-legacy -D
npm i terser -D

使用yarn

sql 复制代码
yarn add @vitejs/plugin-legacy -D
yarn add terser -D

使用pnpm

sql 复制代码
pnpm add @vitejs/plugin-legacy -D
pnpm add terser -D
2、配置vite.config.ts文件
javascript 复制代码
// vite.config.ts 
import { defineConfig } from 'vite' 
import vue from '@vitejs/plugin-vue' 
import legacy from '@vitejs/plugin-legacy'
​
// https://vitejs.dev/config/ 
export default defineConfig({ 
    plugins: [vue(), 
        legacy({
            targets: ['defaults', 'Chrome >= 64'], // 指定需要支持的浏览器版本
            additionalLegacyPolyfills: ['regenerator-runtime/runtime'], // 可选, 额外的 polyfill 需要安装
            renderLegacyChunks: true, // 可选,是否生成传统版本的 chunk,默认true
            // 可选,不配置使用默认。具体的 polyfill 列表
            polyfills: [
                'es.symbol',
                'es.array.filter',
                'es.promise',
                'es.promise.finally',
                'es.object.assign',
                'es.map',
                'es.set',
                'es.array.for-each',
                'es.object.define-properties',
                'es.object.define-property',
                'es.object.get-own-property-descriptor',
                'es.object.get-own-property-descriptors',
                'es.object.keys',
                'es.object.to-string',
                'web.dom-collections.for-each',
                'esnext.global-this',
                'esnext.string.match-all',
                'es.array.iterator',
                'es.string.includes',
                'es.string.starts-with',
                'es.object.values',
            ]
        })
    ], 
    // 配置打包后的目标esm的版本
    build: { 
        minify: "terser", // 使用 terser 进行压缩
    } 
})

legacy插件中如果我们没有指定targets参数时,插件会默认的取项目中的支持的浏览器范围的文件 .browserslistrc,个人对此进行了一个大概的配置

复制代码
Chrome >= 51 
Edge >= 15 
Safari >= 10 
Firefox >= 54 
Opera >= 38 
iOS >= 10 
not ie <= 11 
Android >= 5 
not IE <= 11

更多配置请参考 legacy官方文档

3、构建

通过npm run build打包可以看到script发生了变化,除了type="module"还有一个nomodule脚本,nomodule这个属性表示在支持esm的浏览器不运行里面的代码,而不支持esm的浏览器又无法识别type="module",反而会去运行nomodule的script,从而实现了降级区分。而降级的脚本都会携带一个legacy文本。

大概效果如下:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
​
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/favicon.ico">
  <link rel="stylesheet" href="https://printjs-4de6.kxcdn.com/print.min.css">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite App</title>
  <script type="module" crossorigin src="/assets/index-BUwO137t.js"></script>
  <link rel="stylesheet" crossorigin href="/assets/index-BsmRYvi8.css">
  <script type="module">import.meta.url;import("_").catch(()=>1);(async function*(){})().next();if(location.protocol!="file:"){window.__vite_is_modern_browser=true}</script>
  <script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
</head>
​
<body>
  <div id="app"></div>
  <script src="https://printjs-4de6.kxcdn.com/print.min.js"></script>
    
  <!-- 这里是legacy处理后的 -->
  <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
  <script nomodule crossorigin id="vite-legacy-polyfill" src="assets/polyfills-legacy-BuMl3xCl.js"></script>
  <script nomodule crossorigin id="vite-legacy-entry" data-src="assets/index-legacy-BrIJujGY.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>

二、CSS兼容


推荐使用 postcss-preset-env 插件

推荐原因:

  • 自动添加浏览器前缀
  • 减少手动工作
  • 无缝集成
  • 提高兼容性和性能

官方地址

项目地址

集成
1、安装依赖

使用npm

css 复制代码
npm i postcss-preset-env -D

使用yarn

csharp 复制代码
yarn add postcss-preset-env -D

使用pnpm

csharp 复制代码
pnpm add postcss-preset-env -D
2、配置文件vite.config.ts
javascript 复制代码
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import poscssPresetEnv from "postcss-preset-env";
​
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  css: {
    postcss: {
      // ⚠️关键代码
      plugins: [
        poscssPresetEnv({
          stage: 1, // 配置阶段,1 表示启用大多数新特性
          features: {
            "nesting-rules": true, // 启用嵌套规则
            "custom-properties": true, // 启用自定义属性
            // 其他特性配置
          },
          // 启用 autoprefixer
          autoprefixer: {
            grid: true
          },
          // 一定要指定浏览器版本,否则autoprefixer将无法正确处理
          browsers: ["last 2 versions", "ie >= 11"],
        }),
      ],
    },
  },
});
​
3、构建

打包前:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
​
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/favicon.ico">
  <link rel="stylesheet" href="https://printjs-4de6.kxcdn.com/print.min.css">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite App</title>
</head>
​
<body>
  <div id="app"></div>
</body>
​
<style>
  :root {
    --main-color: '#fef'
  }
​
  .card {
    width: 240px;
    margin: 10px;
    border: 1px solid #ccc;
    box-shadow: 2px 2px 6px 0px rgba(0, 0, 0, 0.3);
    border-radius: 10px;
    padding: 10px;
    transition: all .3s;
    display: grid;
​
    &:hover {
      color: var(--main-color);
​
    }
  }
​
  .buttom {
    display: flex;
    align-items: center;
    justify-content: center;
  }
</style>
</html>

打包后:

可以看到对自定义属性 --main-color 的使用,会多一种兼容写法;对box-shadow transition flex 等属性,自动添加了浏览器的内核的前缀

xml 复制代码
<!DOCTYPE html>
<html lang="en">
​
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/favicon.ico">
  <link rel="stylesheet" href="https://printjs-4de6.kxcdn.com/print.min.css">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite App</title>
</head>
​
<body>
  <div id="app"></div>
</body>
​
<style>
  :root {
    --main-color: '#fef'
  }
​
  .card {
    width: 240px;
    margin: 10px;
    border: 1px solid #ccc;
    -webkit-box-shadow: 2px 2px 6px 0px rgba(0, 0, 0, 0.3);
    box-shadow: 2px 2px 6px 0px rgba(0, 0, 0, 0.3);
    border-radius: 10px;
    padding: 10px;
    -webkit-transition: all .3s;
    transition: all .3s;
    display: grid;
  }
​
  .card:hover {
      color: '#fef';
      color: var(--main-color);
    }
​
  .buttom {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
  }
</style>
</html>

三、CSS原子化插件


推荐使用 unocss

推荐原因:unocss是一个css引擎,unocss本身不提供任何类名css,它只是解决Tailwind以及Windi的编译和打包的某些问题,也就是它可以配合Tailwind或者windi使用,以提供更快的编译打包速度。可以在开发中尽可能的减少自定义样式的编写。

参考页面:unocss.dev/guide/

集成
1、安装依赖

使用npm

css 复制代码
npm i unocss -D

使用yarn

csharp 复制代码
yarn add unocss -D

使用pnpm

csharp 复制代码
pnpm add unocss -D
2、配置文件
  • 创建一个 uno.config.ts 文件
javascript 复制代码
// uno.config.ts
import { defineConfig } from 'unocss'
​
export default defineConfig({
  // ...UnoCSS options
})
  • 配置 vite.config.ts 文件
javascript 复制代码
// vite.config.ts
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vite'
​
export default defineConfig({
  plugins: [
    UnoCSS(),
  ],
})
  • 在入口页面导入,一般为 main.ts
arduino 复制代码
import 'virtual:uno.css'
3、额外配置:

推荐VSCode下载一个扩展 UnoCSS 可以在开发过程中有很好的提示效果。

相关推荐
拉不动的猪2 分钟前
# 关于初学者对于JS异步编程十大误区
前端·javascript·面试
玖釉-7 分钟前
解决PowerShell执行策略导致的npm脚本无法运行问题
前端·npm·node.js
Larcher41 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐1 小时前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭1 小时前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信2 小时前
我们需要了解的Web Workers
前端
brzhang2 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu2 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花2 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js