阅读视图

发现新文章,点击刷新页面。

每日一题-整数的镜像距离🟢

给你一个整数 n

定义它的 镜像距离 为:abs(n - reverse(n)),其中 reverse(n) 表示将 n 的数字反转后形成的整数。

返回表示 n 的镜像距离的整数。

其中,abs(x) 表示 x 的绝对值。

 

示例 1:

输入: n = 25

输出: 27

解释:

  • reverse(25) = 52
  • 因此,答案为 abs(25 - 52) = 27

示例 2:

输入: n = 10

输出: 9

解释:

  • reverse(10) = 01,即 1。
  • 因此,答案为 abs(10 - 1) = 9

示例 3:

输入: n = 7

输出: 0

解释:

  • reverse(7) = 7
  • 因此,答案为 abs(7 - 7) = 0

 

提示:

  • 1 <= n <= 109

3783. 整数的镜像距离

解法

思路和算法

整数 $n$ 反转的结果为 $\textit{reverse}(n)$,计算 $|n - \textit{reverse}(n)|$ 即可。

计算 $\textit{reverse}(n)$ 的方法为:从低到高遍历整数 $n$ 的每一位,将每一位根据遍历顺序从高到低填入反转后的数字。

代码

###Java

class Solution {
    public int mirrorDistance(int n) {
        return Math.abs(n - reverse(n));
    }

    public int reverse(int n) {
        int reversed = 0;
        while (n != 0) {
            reversed = reversed * 10 + n % 10;
            n /= 10;
        }
        return reversed;
    }
}

###C#

public class Solution {
    public int MirrorDistance(int n) {
        return Math.Abs(n - Reverse(n));
    }

    public int Reverse(int n) {
        int reversed = 0;
        while (n != 0) {
            reversed = reversed * 10 + n % 10;
            n /= 10;
        }
        return reversed;
    }
}

###C++

class Solution {
public:
    int mirrorDistance(int n) {
        return abs(n - reverse(n));
    }

    int reverse(int n) {
        int reversed = 0;
        while (n) {
            reversed = reversed * 10 + n % 10;
            n /= 10;
        }
        return reversed;
    }
};

###Python

class Solution:
    def mirrorDistance(self, n: int) -> int:
        def reverse(n: int) -> int:
            reversed = 0
            while n:
                reversed = reversed * 10 + n % 10
                n //= 10
            return reversed
        return abs(n - reverse(n))

###C

int reverse(int n) {
    int reversed = 0;
    while (n) {
        reversed = reversed * 10 + n % 10;
        n /= 10;
    }
    return reversed;
}

int mirrorDistance(int n) {
    return abs(n - reverse(n));
}

###Go

func mirrorDistance(n int) int {
    return abs(n - reverse(n))
}

func abs(n int) int {
    if n >= 0 {
        return n
    } else {
        return -n
    }
}

func reverse(n int) int {
    reversed := 0
    for n != 0 {
        reversed = reversed * 10 + n % 10
        n /= 10
    }
    return reversed
}

###JavaScript

var mirrorDistance = function(n) {
    return Math.abs(n - reverse(n));
};

var reverse = function(n) {
    let reversed = 0;
    while (n) {
        reversed = reversed * 10 + n % 10;
        n = Math.floor(n / 10);
    }
    return reversed;
};

###TypeScript

function mirrorDistance(n: number): number {
    return Math.abs(n - reverse(n));
};

function reverse(n: number): number {
    let reversed = 0;
    while (n) {
        reversed = reversed * 10 + n % 10;
        n = Math.floor(n / 10);
    }
    return reversed;
};

复杂度分析

  • 时间复杂度:$O(\log_{10} n)$,其中 $n$ 是给定的数字。整数 $n$ 的位数是 $O(\log_{10} n)$,需要遍历整数 $n$ 的每一位。

  • 空间复杂度:$O(1)$。

反转数字(Python/Java/C++/Go)

不断地把 $n$ 除以 $10$(下取整)直到 $0$,例如 $123\to 12\to 1\to 0$。在这个过程中的 $d = n\bmod 10$,即为每个数位。

计算 $\textit{rev} \cdot 10 + d$,可以把数字 $d$ 添加到 $\textit{rev}$ 的末尾。例如 $32\cdot 10 + 1 = 321$。

本题视频讲解,欢迎点赞关注~

###py

class Solution:
    def mirrorDistance(self, n: int) -> int:
        rev = int(str(n)[::-1])
        return abs(n - rev)

###py

class Solution:
    def mirrorDistance(self, n: int) -> int:
        rev = 0
        x = n
        while x > 0:
            x, d = divmod(x, 10)
            rev = rev * 10 + d
        return abs(n - rev)

###java

class Solution {
    public int mirrorDistance(int n) {
        int rev = 0;
        for (int x = n; x > 0; x /= 10) {
            rev = rev * 10 + x % 10;
        }
        return Math.abs(n - rev);
    }
}

###cpp

class Solution {
public:
    int mirrorDistance(int n) {
        int rev = 0;
        for (int x = n; x > 0; x /= 10) {
            rev = rev * 10 + x % 10;
        }
        return abs(n - rev);
    }
};

###go

func mirrorDistance(n int) int {
rev := 0
for x := n; x > 0; x /= 10 {
rev = rev*10 + x%10
}
return abs(n - rev)
}

func abs(x int) int { if x < 0 { return -x }; return x }

复杂度分析

  • 时间复杂度:$\mathcal{O}(\log n)$。循环次数等于 $n$ 的十进制长度 $\mathcal{O}(\log n)$。
  • 空间复杂度:$\mathcal{O}(\log n)$ 或 $\mathcal{O}(1)$,取决于是否使用字符串。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

模拟

Problem: 100942. 整数的镜像距离

[TOC]

思路

按题意模拟计算。

Code

执行用时分布0ms击败100.00%;消耗内存分布8.36MB击败52.83%

###C

int mirrorDistance(int n) {
    int n1 = 0;
    for (int x = n; x; x /= 10)
        n1 = n1 * 10 + x % 10;
    return abs(n - n1);
}

###Python3

class Solution:
    def mirrorDistance(self, n: int) -> int:
        return abs(n - int(str(n)[::-1]))

深度解密 Rollup 插件开发:核心钩子函数全生命周期图鉴

前言

Rollup 的强大在于其精简的插件系统。一个 Rollup 插件本质上就是一个包含各种“钩子函数”的对象。理解这些钩子的执行时序,是编写高性能插件、优化构建流程的关键。本文将带你深度复盘 Rollup 的两大核心阶段:构建 (Build)输出 (Output)


一、构建阶段钩子函数(核心阶段)

构建阶段主要负责模块的解析、加载和转换,最终完成模块依赖图的构建,是Rollup打包的基础。该阶段可细分为5个小阶段,钩子执行顺序固定为:

初始化阶段(options、buildStart)→ 模块加载阶段(resolveId、load)→ 模块转换阶段(transform、moduleParsed)→ 代码生成阶段(augmentChunkHash、resolveDynamicImport)→ 代码构建阶段(buildEnd)

1. 初始化阶段钩子(options、buildStart)

options

  • 执行时机:在读取用户配置之后、构建开始之前执行。

  • 作用:可以添加或修改默认配置项(如调整input、output、plugins等Rollup核心配置)。

  • 注意:仅支持同步执行,无法进行异步操作;此钩子修改的配置会覆盖用户默认配置,需谨慎使用。

buildStart

  • 执行时机:开始解析模块前执行(构建流程启动的第一个核心钩子)。

  • 作用:用于初始化插件状态(如重置计数器、初始化缓存)、读取外部文件(如配置文件、静态资源清单)等。

  • 支持:同步、异步执行(可返回Promise);此钩子可访问传递给rollup.rollup()的最终配置,包含所有options钩子的转换结果和默认值。

2. 模块加载阶段钩子(resolveId、load)

resolveId(source, importer)

  • 执行时机:它是在Rollup遇到一个 import 语句时(如 import foo from './foo.js')执行,是模块解析的核心钩子。

  • 作用:它可以将模块标识符(如 './foo.js''vue')解析为绝对路径或模块 ID,返回一个解析后的路径ID(返回值可以是 null、string 或者一个对象,如果返回false则视为外部模块,不打包)。支持同步、异步执行。

  • 入参说明:

    • source:表示 import 的内容(字符串),即模块标识符;
    • importer:表示导入该模块的文件路径(绝对路径),入口文件的importer为 null。

如果多个插件都定义了resolveId,会按插件配置顺序执行,直到某个插件返回非null/undefined的值(表示解析完成);也可通过配置order: 'pre'调整钩子执行优先级,实现优先解析特定模块。

示例:拦截虚拟模块导入,自定义模块解析逻辑:

resolveId(source) {
  if (source === 'virtual-module') {
    // 表示rollup不应询问其他插件或从文件系统检查此ID
    return source;
  }
  return null; // 其他ID按正常逻辑处理
}

load(id)

  • 执行时机:它在 resolveId 返回一个 ID 后执行,是模块加载的核心钩子。

  • 作用:用于获取对应模块的源码,并返回这个源码给transform钩子进行后续转换。

  • 支持:同步、异步执行;若返回null,Rollup会默认从文件系统读取该ID对应的文件内容,也可通过this.load在其他钩子中触发模块预加载。

示例:自定义虚拟模块的源码加载:

load(id) {
  if (id === 'virtual-module') {
    // 返回虚拟模块的源码
    return 'export default "This is virtual!"';
  }
  return null; // 其他ID按正常逻辑加载
}

3. 模块转换阶段钩子(transform、moduleParsed)

transform(code, id)

  • 执行时机:它在模块源码加载后执行,紧随load钩子之后。

  • 作用:它用于将模块源码中的ts、tsx等非标准JS语法转换为标准的js语法,也可对源码进行压缩、注入代码等自定义处理。支持同步、异步执行

  • 入参说明:

    • code:模块的源码字符串(load钩子返回的内容);
    • id:模块 ID(通常是文件路径,与resolveId返回的ID一致)。
  • 返回值:{ code: '修改后的代码', map: 'sourcemap' },其中sourcemap可选,用于关联转换后的代码与原始源码,方便调试。

moduleParsed

  • 执行时机:在模块被 Rollup 解析为 AST(抽象语法树)后执行。

  • 作用:可以用于分析模块信息(如导入导出关系)、收集元数据(如模块依赖、变量声明),实际开发中较少使用。

  • 支持:同步、异步执行;入参为moduleInfo,包含当前模块的详细信息,执行完成后会并行解析模块中所有静态和动态导入的依赖。

4. 代码生成阶段钩子(augmentChunkHash、resolveDynamicImport)

augmentChunkHash

  • 执行时机:在生成 chunk 哈希前执行(chunk 哈希用于实现静态资源长效缓存)。

  • 作用:可以向 chunk 哈希添加额外信息(如插件版本、配置参数),确保当这些信息变化时,chunk 哈希也会更新,避免缓存失效不及时。

resolveDynamicImport

执行时机:当遇到动态导入语句时(如import('./foo.js'))执行。

作用:处理动态导入的解析,作用和resolveId类似,但专用于动态导入场景,可自定义动态导入的模块解析规则。

5. 代码构建阶段钩子(buildEnd)

  • 执行时机:构建结束(无论成功或失败)执行,是构建阶段的最后一个钩子。

  • 作用:用于清理资源(如关闭文件流、清空缓存)、上报错误(如构建失败日志上报)等。

  • 支持:同步、异步执行。

二、打包阶段钩子函数(产物输出阶段)

打包阶段主要负责将构建阶段处理后的模块,生成最终的可部署产物,并写入磁盘,钩子执行顺序固定为:

输出生成(renderStart→renderChunk→generateBundle)→ 输出写入(writeBundle→closeBundle)

1. 输出生成阶段钩子(renderStart、renderChunk、generateBundle)

renderStart

  • 执行时机:开始生成 chunk 内容前执行,是打包阶段的第一个钩子。

  • 作用:初始化输出相关状态(如初始化产物计数器、设置输出格式相关参数)。

  • 支持:同步、异步执行。

renderChunk(code, chunk, options)

  • 执行时机:它是在每个 chunk 生成后、写入磁盘前执行。

  • 作用:它可以对生成的chunk 中的JS 代码进行最后处理(例如注入版权注释、补充全局变量、代码压缩优化等)。支持同步、异步执行。

  • 入参说明:

    • code:当前chunk生成后的JS代码字符串;
    • chunk:当前chunk的详细信息(如chunk名称、包含的模块、依赖关系等);
    • options:当前的输出配置(与output配置一致)。

generateBundle

  • 执行时机:它是在所有 chunk 和 asset 生成完毕,即将写入磁盘前执行。

  • 作用:这个钩子的入参里面会包含所有的打包产物信息,包括 chunk (打包后的代码)、asset(最终的静态资源文件)。可以在这里检查、修改、添加最终输出文件(例如删除无用 chunk、合并CSS、注入 preload 链接到 HTML)。

  • 支持同步、异步执行;是打包阶段最常用的钩子之一,可用于最终产物的自定义优化。

2. 输出写入阶段钩子(writeBundle、closeBundle)

writeBundle

  • 执行时机:它是在bundle 已写入磁盘后执行,仅在调用bundle.generate()bundle.write() 时触发。

  • 作用:可以在这执行写入后的操作(如将产物上传 CDN、生成产物清单、通知部署服务等)。

  • 支持:同步、异步执行。

closeBundle

  • 执行时机:它是在整个构建完全结束执行,是Rollup打包流程的最后一个钩子。

  • 作用:可以在这做一些全局清理操作(如关闭数据库连接、清空临时文件、终止子进程等)。

  • 支持:同步、异步执行;无论构建成功或失败,都会执行此钩子。

三、钩子执行顺序(核心重点)

// 完整执行顺序
options → buildStart → resolveId → load → transform → moduleParsed → 
augmentChunkHash → resolveDynamicImport → buildEnd → renderStart → 
renderChunk → generateBundle → writeBundle → closeBundle

注意:所有钩子均支持同步执行,标注“支持异步”的钩子可返回Promise,实现异步操作(如读取外部文件、请求接口);多个插件定义同一钩子时,按插件配置顺序执行。

四、补充

  1. 钩子使用场景:开发Rollup插件时,可根据需求选择对应阶段的钩子(如语法转换用transform、产物优化用generateBundle、CDN上传用writeBundle);

  2. 与Vite关联:Vite生产环境基于Rollup打包,Vite插件可直接使用Rollup的所有钩子,同时Vite会自动注入内置插件,无需手动配置基础钩子(如resolveId、load);

  3. 调试技巧:可在钩子中打印日志(如console.log('钩子执行:', id)),查看钩子执行顺序和入参信息,快速排查插件问题。

深度解析 Rollup 配置与 Vite 生产构建流程

前言

为什么 Vite 在生产环境不使用 ESBuild 而是选择 Rollup?为什么 Rollup 打包出来的代码比 Webpack 更纯粹?本文将带你深入 Rollup 的核心配置,并拆解 Vite 是如何驱动 Rollup 完成生产环境构建的。

一、 Rollup 核心配置:构建系统的“方向盘”

1. 核心概念

Rollup 是 Vite 生产环境下的底层打包工具,专注于 ES 模块的打包优化。

注意:在 Vite 项目中,不需要单独编写rollup.config.js文件,所有 Rollup 相关的配置都统一写在vite.config.js/tsbuild.rollupOptions字段中。Vite 会自动将你的配置与内置的 Rollup 配置合并,生成最终的打包配置。

2. 核心特点

  • 具有天然的 Tree Shaking 功能,可以静态分析 ES 模块的导入导出关系,精准移除未使用到的代码
  • 支持Scope Hoisting(作用域提升) ,将多个模块的代码合并到同一个作用域中,减少函数包裹和运行时开销
  • 打包产物体积小、执行效率高,特别适合用于 JavaScript 库和工具的打包
  • 插件系统简洁强大,易于扩展和定制

二、Rollup 核心配置项详解

1. input(打包入口)

用于指定打包的入口文件,支持三种写法:

  • 字符串:单入口,所有代码打包到一个文件中,适合 SPA 单页面应用
  • 数组:多入口,每个入口生成独立的 chunk 文件,公共依赖会自动拆分
  • 对象:多入口,可自定义每个 chunk 的名称,是最灵活的写法
// 单入口
input: 'src/index.js'

// 数组多入口
input: ['src/page1.js', 'src/page2.js']

// 对象多入口(推荐)
input: {
  home: 'src/pages/home.js',
  about: 'src/pages/about.js',
  vendor: 'src/utils/vendor.js'
}

原内容保留:如果是多文件的话,会给每个入口生成独立文件,公共依赖会在打包过程中拆分出来,适用于 MPA(多页应用)、库的多版本。

2. output(打包输出)

该属性为对象或对象数组类型,可以指定打包后的文件输出规则。如果配置为数组,可以将同一份代码打包成多种不同格式的包同时输出。output 核心属性如下:

属性名 类型 说明
dir string 输出目录,当有多个 chunk 时必须使用此属性
file string 单个输出文件的路径,仅适用于单入口单 chunk 的情况
format string 输出格式,支持:- esm:ES Module 格式(Vite 默认)- cjs:CommonJS 格式- umd:通用模块定义- iife:立即执行函数格式
name string 打包为iifeumd格式时必须配置,指定对外暴露的全局变量名
globals object 全局变量声明,用于将外部依赖映射为全局变量示例:{ jquery: '$' }表示项目中可以直接用$代替jquery
sourcemap boolean 是否生成源码映射文件,方便生产环境调试
assetFileNames string 静态资源文件输出文件名模板示例:'assets/[name]-[hash][extname]'

下面的例子代表第一次打包(ESM 格式),将结果输出到dist/es/目录,第二次打包(CJS 格式),将结果输出到dist/cjs/目录

output: [
  {
    dir: "dist/es",    // 输出到 dist/es 目录
    format: "esm",     // ES Module 格式
  },
  {
    dir: "dist/cjs",   // 输出到 dist/cjs 目录
    format: "cjs",     // CommonJS 格式
  },
]

3. external(外部依赖)

用于标记某些模块为外部依赖,告诉 Rollup 这些模块不应该被打包到最终的 bundle 中。对于某些第三方包,有时候我们不想让 Rollup 进行打包,也可以通过 external 进行外部化。external 支持三种写法:

// 字符串写法
external: ['vue', 'react']

// 正则写法
external: [/^lodash/]

// 函数写法(最灵活)
external: (id) => {
  // 所有node_modules中的模块都标记为外部依赖
  return id.includes('node_modules')
}

使用场景

  • 库打包时,将核心依赖(如 Vue、React)外部化,避免重复打包
  • 减少打包体积,提高构建速度
  • 利用 CDN 加载公共依赖

4. plugins(插件系统)

用于扩展和定制 Rollup 的构建流程。该配置项可以与output配置在同一级(全局生效),也可以配置在 output 参数里面(仅对该输出生效)。可使用自定义编写的 Rollup 插件,也可以使用第三方插件。

常用 Rollup 插件整理如下:

插件名称 作用
@rollup/plugin-json 支持.json文件的加载,并配合 Tree Shaking 去掉未使用的部分
@rollup/plugin-babel 使用 Babel 进行 JS 代码的语法转译,兼容低版本浏览器
@rollup/plugin-typescript 支持使用 TypeScript 开发
@rollup/plugin-alias 支持路径别名配置
@rollup/plugin-replace 在打包过程中进行变量字符串的替换
@rollup/plugin-node-resolve 解析 node_modules 中的第三方依赖
@rollup/plugin-commonjs 将 CommonJS 模块转换为 ES 模块,供 Rollup 处理
rollup-plugin-visualizer 对打包产物进行分析,自动生成产物体积可视化分析图

补充说明@rollup/plugin-node-resolve@rollup/plugin-commonjs是 Rollup 处理第三方依赖的必备插件,Vite 已经内置了这两个插件,不需要手动配置。

这篇笔记非常深入地探讨了 Rollup 在 Vite 体系中的地位。作为现代前端打包工具的“幕后英雄”,Rollup 的配置和流程是进阶高级前端的必修课。

为了适配掘金的风格,我为你优化了标题,并引入了“声明式配置图解”和“双阶段构建流”的概念,同时修正了部分关于 input 拼写的小细节。


进阶必备:深度解析 Rollup 配置与 Vite 生产构建流程

前言

为什么 Vite 在生产环境不使用 ESBuild 而是选择 Rollup?为什么 Rollup 打包出来的代码比 Webpack 更纯粹?本文将带你深入 Rollup 的核心配置,并拆解 Vite 是如何驱动 Rollup 完成生产环境构建的。


一、 Rollup 核心配置:构建系统的“方向盘”

Rollup 的配置以简洁著称,其设计的核心目标是打包出最干净的代码库

1. 入口与出口 (Input & Output)

  • input (注意是单数):支持字符串或数组/对象。

    • 单入口:适合单页面应用 (SPA),生成一个主 bundle。
    • 多入口:适合多页面应用 (MPA) 或组件库,Rollup 会自动提取公共依赖。
  • output:支持数组形式,实现一份源码,多种格式输出

    • format:

      • esm: 现代浏览器首选。
      • cjs: Node.js 环境使用。
      • umd: 兼容 AMD/CommonJS/全局变量。
    • globals: 映射外部依赖,如 { jquery: '$' }

2. 外部依赖 (External)

核心作用:标记某些模块不被打包。

  • 场景:在开发组件库时,通常会将 vuereact 设为 external,让宿主环境提供这些依赖,减小打包体积。

3. 常用插件全家桶

插件名称 核心作用
@rollup/plugin-json 让 JS 能直接 import json,并支持 Tree Shaking。
@rollup/plugin-babel 配合 Babel 进行语法降级,解决兼容性问题。
@rollup/plugin-typescript 让 Rollup 具备处理 TS 的能力。
@rollup/plugin-alias 配置路径别名(如 @ 指向 src)。
rollup-plugin-visualizer 神器:生成体积分析图,优化首屏加载必看。

三、 Vite 视角下的 Rollup 构建流程

执行vite build命令后,Vite 会先完成自身的预处理工作,然后将所有打包任务委托给 Rollup 执行。整个流程可以分为以下三个核心阶段:

阶段 1:Vite 配置预处理与 Rollup 配置生成

Vite 读取vite.config.js,先分离 Vite 非 Rollup 相关的配置和 Rollup 相关配置;将 Vite 内置的处理 Vue/TS/CSS/ 静态资源插件注入,再合并用户配置的插件,最终生成标准的包含inputoutputplugins等核心字段的Rollup 配置对象

接着 Vite 调用 Rollup 的rollup.rollup()方法,传入上述配置,启动 Rollup 构建流程。

阶段 2:Rollup 构建阶段(建立模块依赖图)

Rollup 从input指定的入口文件开始,依次执行所有插件的resolveId(解析模块路径)→load(加载文件内容)→transform(转换文件为标准 ES 模块)钩子来处理各类资源。在处理的过程中会递归解析所有导入的模块,直到所有依赖解析完成,建立完整的模块依赖图。

补充:这个阶段只进行模块的解析和转换,不会生成任何输出文件。所有的文件内容都会被加载到内存中,形成一个完整的模块树。

阶段 3:Rollup 生成阶段(产物生成与输出)

在构建打包的过程中,Vite 会基于模块依赖图执行 Tree-shaking 移除未使用代码、Scope Hoisting 作用域提升,并根据output配置进行代码分割将代码拆分成多个独立的 chunks 文件,实现按需加载。Vite 插件在此阶段补充处理(将.vue、.ts 等文件编译为标准的 js 文件、并处理 css 将其压缩成单独的 css 文件等)。

最后调用bundle.generate()在内存中生成编译后的 JS/CSS/HTML 等产物,和bundle.write()将内存中的产物写入磁盘(默认dist目录),最终生成可部署的静态资源文件。

补充bundle.generate()只在内存中生成产物,不写入磁盘;bundle.write()会先调用bundle.generate(),然后将产物写入到指定的输出目录。

总结

Rollup 作为 Vite 生产环境的底层打包工具,是理解 Vite 打包原理的关键。掌握 Rollup 的核心配置和构建流程,不仅能帮助你解决生产环境中的各种打包问题,还能让你更灵活地定制 Vite 的构建流程,实现更高效的打包优化和插件开发。

35.68 万元起,1400 匹马力、零百 2.9 秒的极氪 8X,要做新能源时代的「公路之王」

过往几年,中国新能源汽车在舒适、智能、科技等维度上实现了弯道超车,取得了堪称举世瞩目的成就。

但如果提起极致的高性能旗舰中大型 SUV,人们第一时间想到的,往往还是燃油车时代的经典图腾——宝马 M、奔驰 AMG 以及保时捷们。

众所周知,高性能一直以来都是全球超豪华汽车品牌的「通用语言」,它展现着一家车企的造车底蕴、技术积累与品牌文化。

正因如此,当历史的车轮驶入新能源时代,中国汽车工业也需要一款能够代表全球顶尖水准的「性能图腾」。于是,站在吉利集团创业 40 周年、造车近 30 周年的历史节点上,极氪 8X 出现了。

极氪认为,曾经的高性能豪华 SUV,往往伴随着妥协:动力迅猛却难兼顾极致操控与舒适;越野强悍却在城市穿梭时显得笨重;车身坚硬却在智能交互上落后于时代。

但极氪 8X 的诞生,就是要挑战「既要、又要、还要」的技术极限,在三电、底盘、安全与智能化领域同时做到最强。

极氪 8X 一共推出了 4 个版本,起售价为 35.68 万元。

性能旗舰

极氪 8X 搭载了 SEP 浩瀚超级电混系统,采用 900V 混动高压架构。

在此架构下,极致的曜影版综合最大功率达 1030kW,马力超过 1400 匹,并匹配了一台最大功率 205kW 的 2.0T 混动专用发动机,以及峰值功率达到 145kW 的 P1 发电机。

搭载三电机系统的极氪 8X 曜影版百公里加速时间仅需 2.96 秒,这也是目前极少数能将零百加速推进「2 秒俱乐部」的中大型混动 SUV;普通双电机版本的零百加速也达到了 3.7 秒。

当然除了爆发力,补能和持续性能也是插混车型的重要指标。

极氪 8X 配备了支持 6C 超充的大容量电池包。得益于 900V 架构的放电能力,车辆在电池馈电状态下依然能保持较高的动力输出。据极氪官方透露,即使在馈电工况下,极氪 8X 的百公里加速表现依然能够优于宝马 X5M 和保时捷 Cayenne 等传统燃油性能标杆。

在激烈驾驶场景下,极氪 8X 通过前后四个电机协同分摊电池供电压力,配合发电机实时补能,让高强度输出下的动力表现更为稳定持续。

根据配置不同,极氪 8X 提供 55.1kWh 与 70kWh 两种电池规格,纯电续航分别为 256km、257km、328km,新车同时支持支持 900V 6C 超快充,常温下从 20% 到 80% 仅需约 9 分钟。

尽管整备质量接近 3 吨,极氪 8X 在 WLTC 工况下的馈电油耗仍可控制在约 7L/100km,综合续航超过 1200km。

同时,极氪 8X 采用了同级少见的闭式双腔空气悬架和双阀 CCD 电磁减振系统,并引入了以往多见于百万级高端性能车上的主动防倾杆。得益于这套机械组合,车辆在以 80km/h 的时速进行高速过弯时,车身侧倾角可被抑制在 2 度以内。

结合浩瀚 AI 数字底盘和定海智能中枢,极氪 8X 够调用整车的算力资源,将原本相互独立的动力总成、悬架系统、制动、转向以及辅助驾驶系统进行底层打通,实现实时感知与精准执行,在面临车辆高速爆胎等极其危险的突发状况时,系统能瞬间将空气弹簧的刚度提升 30% 以上,并迅速降低车身重心,以最大程度保障车辆的操控稳定性与乘员安全。

此外,这套底盘系统不仅服务于公路驾驶,也兼顾了非铺装路面的场景需求。针对沙地、草地、岩石、冰雪等复杂的越野路况,系统能够进行自适应的模式切换与动力分配,使这台定位于公路性能的旗舰 SUV,在面对全地形挑战时也能具备一定的应对能力。

安全旗舰

在高端中大型 SUV 领域,安全性能始终是衡量产品核心竞争力的重要基石。依托吉利集团内部深厚的造车积淀,极氪 8X 在被动车身与主动防御层面均进行了较高规格的冗余设计。

在被动车身结构上,极氪 8X 采用了行业少见的「一体式双门环」架构。这种设计有效减少了传统拼接工艺带来的结构薄弱点,使得 A 柱、B 柱、C 柱以及下方的门槛梁能够更好地协同受力,分散碰撞能量。

同时,车辆在关键的 A/B 柱区域首创了夹心设计,内部嵌有抗拉强度高达 2000MPa 的热气胀管作为核心支撑,配合极氪自研的一体式压铸后车身技术,整车的扭转刚度达到了 42,400 N·m/deg,为乘员舱提供了极高的物理抗压能力。

极氪 8X 同时将底盘硬件与被动安全进行了联动,当系统感知到侧方即将发生不可避免的碰撞时,其搭载的主动防倾杆能够在 0.7 秒内紧急抬升受击侧的车身,迫使车辆以最为坚固的门槛梁去硬扛撞击力。

针对新能源汽车核心的电池安全,极氪 8X 构建了一套被称为「985」的立体防护体系,即侧面 9 层、底部 8 层、顶部 5 层的结构支撑。面对日常驾驶中易发生的底盘托底风险,其电池包底部加装了多功能复合高强板,既能分散外部锋利物体的冲击,又能起到内部缓冲的作用,最大限度保障电芯的物理安全。

此外,极氪 8X 全系标配了高阶的 GAEB(智能自动紧急制动)与 GAES(智能自动紧急转向)系统,这套系统在高达 130km/h 的高速工况下依然具备出色的识别与响应能力。

此外,车辆还内置了 SOS 紧急停车辅助功能,通过实时监测驾驶员的体征与疲劳状态,系统在发现异常时会进行多梯度的声光唤醒;若驾驶员持续无响应,车辆将自动接管并寻机安全靠边停车。

智能旗舰

在电子电气架构层面,极氪 8X 试图通过底层逻辑的重构来提升整车的智能化上限。

该车首发搭载了 WAM 世界行为模型,打破了传统汽车各个电子模块之间的壁垒,将辅助驾驶域、智能座舱域、底盘域以及动力域进行了底层数据的打通与整合,从而形成一个具备全局调度能力的中央计算中枢。

基于这种跨域融合架构,极氪 8X 在人机交互层面推出了名为「超级 EVA」的智能体。

在功能表现上,超级 EVA 试图摆脱传统车机语音助手「一问一答」的被动执行模式,依托大模型算法的加持,它能够结合车辆环境感知与驾驶决策,实现带有一定场景理解和主动协同的高阶交互。

同时,极氪 8X 依托 Smart AI Agent 架构 WAM 模型,在路径规划与场景感知上进行了大量优化,并落地了手势召唤、AI 终点领航等高阶功能,能够提升复杂场景下的通行效率与便利性。

为了匹配不同层级的智驾需求,极氪 8X 在硬件上划分了 H7 与 H9 两个版本的方案。

H7 搭载单颗英伟达 Thor 芯片,车身外部共配备 30 余个高精度感知元件,H9 升级为双英伟达 Thor 芯片,综合算力高达 1400 TOPS,并配备了多达 5 颗激光雷达,构建了「三重 360 度」的全局环境感知体系。

优雅旗舰

在传统汽车的工程研发中,机械性能与乘坐舒适性往往存在一定的博弈关系:为了追求极致的动力与操控,庞大的高性能动力总成和复杂的悬架结构极易侵占座舱体积。

面对这一行业痛点,极氪 8X 并没有选择粗暴地一味加大车身外尺寸,而是试图依托浩瀚 S 架构的底层整合能力,通过高效率的系统集成与布局优化来释放内部空间。

官方数据显示,极氪 8X 的座舱内部有效面积达到了 5.93 平方米,人均占地面积超过 1.18 平方米。

车辆第二排配备了长度达 150mm 的前后滑轨,这使得用户可以根据实际出行场景,在后排腿部空间与后备厢载物能力之间进行灵活调配。

得益于此,身高 1.8 米的成年人落座后排时,膝部空间依然可达到 200 余毫米。

而在储物能力方面,极氪 8X 的后备厢常规容积达到了 1133 升,在同级车型中处于领先水平,其内部纵深甚至可以直接放入一台无需折叠的标准婴儿车。

在座椅的人体工程学与舒适性配置上,极氪 8X 针对不同位置的乘员需求进行了差异化设计。

为了匹配其高性能的驾驶属性,主驾座椅加入了动态侧翼支撑功能。当车辆在进行快速过弯、变道或急加速等动作时,座椅侧翼能在 0.1 秒内迅速响应并收紧,为驾驶者提供更稳固的身体侧向支撑。

而在后排,极氪 8X 引入了曾在极氪 009 上搭载的「伊姆斯」风格躺椅,其靠背最大倾斜角度可达同级领先的 137 度,配合支持 90 度翻折的超大腿托与脚踏,提升了长途出行的乘坐舒适度。此外,全车座椅均标配了多达 22 个点位的分区按摩系统。

后排顶部则搭载了一块 17 英寸的 OLED 真彩吸顶屏,配合杜比全景声音响系统,构建了一套多维度的车载影院。在播放媒体内容时,这套系统可与车内音响、座椅震动、空调风量、氛围灯以及香氛系统进行实时联动,提供更具沉浸感的视听体验。

为了提升日常用车的便利性与仪式感,极氪 8X 配备了电动脚踏板与电动车门,并支持主驾「踩下制动踏板自动关门」的便捷功能。

同时,车辆在车外照明系统中加入了智能交互光语。除了提供迎宾光毯以及夜间弯道自适应补光外,该系统还能在诸如「斑马线礼让行人」等特定场景下,主动投射相应的提示灯语。

纵观当前的中国新能源豪华 SUV 市场,产品线往往不可避免地陷入「家用舒适」的同质化内卷中。

在这样的大环境下,极氪 8X 选择了另一条路线,打出了一套「极致驾控 + 旗舰豪华」的组合拳。

这种偏向个人驾驶乐趣与硬核机械素质的定位,在当前的细分市场中具有极强的稀缺性,目前市面上几乎鲜有能够在体量、性能与豪华度上与之一对一正面抗衡的同类竞品。

同时,极氪 8X 与极氪 9X 的分工也十分明确,9X 体量更大、取向更舒适,8X 更运动、更紧凑,理论上可以覆盖不同的目标用户圈层。

在竞争烈度持续攀升、产品定义日益雷同的中国新能源市场,选择走一条有别于「纯家用」的差异化道路,不仅需要品牌魄力,更需要断层式的产品力作为底层支撑。

结合 35.68 万元的起售价,以及其在三电系统、机械底盘和高阶智能座舱等维度的硬核配置,极氪 8X 已经展现出了极高的硬件诚意与「性价比」。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

sha256sum and md5sum Commands: Verify File Integrity in Linux

When you download an ISO image, a backup archive, or a large release tarball, there is no easy way to tell by looking whether the file arrived intact. A single flipped bit can break a boot image or turn a compressed archive into junk, and a compromised mirror can serve a tampered file that looks legitimate. The fix is to compare a cryptographic fingerprint of the file against a value the publisher has signed or posted somewhere you trust.

This guide shows how to use sha256sum and md5sum to generate, compare, and verify checksums on Linux, and when to use each one.

sha256sum and md5sum Syntax

Both commands follow the same form:

txt
sha256sum [OPTIONS] [FILE]...
md5sum [OPTIONS] [FILE]...

Without options, each command prints a hex digest followed by two spaces and the file name. Pass -c to verify files against a list of previously generated checksums.

sha256sum vs md5sum

The two tools do the same job: they read a file and print a fixed-length fingerprint. The difference is the algorithm and, by extension, how safe the result is against intentional tampering.

md5sum uses the MD5 algorithm and produces a 128-bit digest. MD5 is fast but has been broken for years: it is possible to construct two different files that share the same MD5 hash. Treat it as a checksum for accidental corruption only, not for authenticity or security.

sha256sum uses SHA-256 from the SHA-2 family and produces a 256-bit digest. It is the default choice for verifying downloads, release artifacts, and anything where the threat model includes a malicious middle party. Most Linux distributions publish SHA256SUMS files next to their ISO images for exactly this reason.

When in doubt, use sha256sum. Reach for md5sum only when a publisher provides MD5 values and nothing stronger, or when you need quick parity checks between known-good files.

Generating a Checksum for a File

To produce a SHA-256 digest for a single file, pass it as an argument:

Terminal
sha256sum ubuntu-24.04.2-desktop-amd64.iso
output
5e38b55d57d94ff029719342357325ed3bda38fa80054f9330dc789cd2d43931 ubuntu-24.04.2-desktop-amd64.iso

The output is one line: the hex digest, two spaces, and the file name. The same file always produces the same digest, so you can run the command again after a copy or a download and compare the values by eye.

md5sum behaves the same way:

Terminal
md5sum ubuntu-24.04.2-desktop-amd64.iso
output
2e3720b76b2f9f96edc43ec4d87d7d52 ubuntu-24.04.2-desktop-amd64.iso

Notice that the MD5 digest is shorter. That is the 128-bit hash encoded in 32 hex characters, compared with 64 hex characters for SHA-256.

Generating Checksums for Multiple Files

Both commands accept any number of file arguments and print one line per file:

Terminal
sha256sum *.tar.gz
output
b2b09c1e04b2a3a4c5d6e7f890123456789abcdef0123456789abcdef01234567 backup-2026-04-01.tar.gz
c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8 backup-2026-04-08.tar.gz

To save the output to a checksum file that you can share or verify later, redirect it:

Terminal
sha256sum *.tar.gz > SHA256SUMS

The resulting SHA256SUMS file can be published alongside the archives, and anyone who downloads them can run a single command to confirm that their copy matches.

Verifying a File Against a Known Checksum

The most common task is to check that a download matches the digest the publisher posted. Distributions usually ship a SHA256SUMS file that lists every release file and its digest. Change into the directory that holds both the archive and the checksum file, then pass -c:

Terminal
sha256sum -c SHA256SUMS
output
ubuntu-24.04.2-desktop-amd64.iso: OK
ubuntu-24.04.2-live-server-amd64.iso: OK

sha256sum reads each line of SHA256SUMS, recomputes the digest for the named file, and prints OK when they match. Any line whose file is missing or whose digest differs prints a clear error and causes the command to exit with a non-zero status, which is convenient in scripts.

When you only care about one file out of many, grep the relevant line into the check:

Terminal
grep "ubuntu-24.04.2-desktop-amd64.iso" SHA256SUMS | sha256sum -c -

The trailing - tells sha256sum to read the checksum list from standard input. This keeps the verification scoped to a single file without creating a second checksum file.

Comparing a File to a Published Digest

Sometimes the publisher does not provide a full SHA256SUMS file but instead shows a single digest on a release page. You can compare it directly without creating a file:

Terminal
echo "5e38b55d57d94ff029719342357325ed3bda38fa80054f9330dc789cd2d43931 ubuntu-24.04.2-desktop-amd64.iso" | sha256sum -c -
output
ubuntu-24.04.2-desktop-amd64.iso: OK

The key detail is the double space between the digest and the file name. That is the exact format sha256sum produces and expects, and a single space will cause the check to fail.

Quiet and Warn Modes

During an automated check, the per-file OK lines can be noisy. The --quiet option suppresses successful lines so only failures appear:

Terminal
sha256sum -c --quiet SHA256SUMS

If every file passes, the command prints nothing and exits with status 0. If a file fails, you see a single failure line and a non-zero exit status, which fits well in a CI job or a backup script.

To flag lines in a checksum file that are not formatted correctly, add --warn. This is helpful when the file was assembled by hand and you want to be sure every entry parses.

Common Options

The flags below are the ones you are likely to use day to day:

  • -c, --check - Read digests from a file and verify each one.
  • -b, --binary - Mark files as binary in the output (default on Linux).
  • -t, --text - Read files in text mode (rare on Linux, kept for portability).
  • --quiet - Suppress OK lines when checking.
  • --status - Print nothing; rely on the exit status alone.
  • --ignore-missing - Skip files listed in the digest file that are not present.
  • --tag - Output BSD-style tagged format, useful when mixing hash algorithms.

md5sum accepts the same flags, which makes it easy to swap one command for the other when the algorithm changes.

Quick Reference

Command Description
sha256sum file.iso Generate a SHA-256 checksum for one file
md5sum file.iso Generate an MD5 checksum for one file
sha256sum *.tar.gz > SHA256SUMS Save checksums for multiple files
sha256sum -c SHA256SUMS Verify files against a checksum list
`grep “file.iso” SHA256SUMS sha256sum -c -`
sha256sum -c --quiet SHA256SUMS Show only failures during verification

Verifying a Download End to End

Putting the pieces together, a typical download check looks like this:

Terminal
wget https://releases.ubuntu.com/24.04/ubuntu-24.04.2-desktop-amd64.iso
wget https://releases.ubuntu.com/24.04/SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMS

The --ignore-missing flag keeps the check focused on the file you actually downloaded instead of failing on every other release listed in SHA256SUMS.

For full confidence, also verify the signature on SHA256SUMS itself using the publisher’s GPG key. A digest is only as trustworthy as the source you got it from, so a signed checksum file closes the loop.

Troubleshooting

Checksum mismatch on a freshly downloaded file
Re-download the file, ideally from a different mirror. The most common cause is a truncated transfer or a network error. If the second download still fails, the file on the mirror may be stale or tampered with, and you should report it to the project.

No such file or directory when running with -c
The names in the checksum file are resolved relative to the current directory. Change into the directory that holds the files, or edit the checksum file to use paths that match where the files live.

improperly formatted checksum line warnings
A single space between the digest and the file name instead of two, trailing whitespace, or Windows line endings will all trip the parser. Run dos2unix on the file or recreate it with sha256sum > SHA256SUMS to reset the format.

The MD5 digest matches but you still do not trust the file
You are right to be cautious. MD5 collisions are practical, so match an MD5 against accidental corruption only. Ask the publisher for a SHA-256 digest or a signed checksum file.

FAQ

Which is faster, sha256sum or md5sum?
md5sum is faster, sometimes noticeably so on large files. The speed difference rarely matters on modern hardware, and it is not a good reason to pick MD5 over SHA-256 for security-sensitive checks.

Can I use sha256sum on a directory?
Not directly. Hash tools operate on files. To produce a digest that represents an entire directory, pipe a deterministic listing such as find ... -type f -print0 | sort -z | xargs -0 sha256sum through another sha256sum.

Where do I find the expected digest for a Linux distro ISO?
Every major distribution publishes a SHA256SUMS or SHA512SUMS file on its download page, usually along with a detached GPG signature. Prefer those files over digests shown in third-party blog posts.

Is sha256sum available by default on Linux?
Yes. Both sha256sum and md5sum ship with the GNU coreutils package, which is installed on every mainstream Linux distribution.

Conclusion

sha256sum should be the default for verifying downloads and backups, with md5sum reserved for quick corruption checks when the publisher provides nothing stronger. When you pair a SHA-256 digest with a signed checksum file and a trusted key, you can answer the question that matters most: did I get the file the publisher actually shipped?

臻镭科技:因信披违规将被实施其他风险警示,股票停牌

36氪获悉,臻镭科技公告,公司于4月17日收到证监会浙江监管局《行政处罚事先告知书》,因披露的年度报告财务指标存在虚假记载,根据相关规定,公司股票将被实施其他风险警示。公司股票将于4月20日停牌1天,4月21日复牌并实施其他风险警示,证券简称变更为“ST臻镭”。实施期间,公司股票不进入风险警示板交易,涨跌幅仍为20%,但投资者当日累计买入数量不得超过50万股。公司表示已对相关会计差错进行更正及整改,未触及重大违法强制退市情形,将在满足条件后申请撤销风险警示。

加拿大邮政将终止住宅邮件投递

加拿大邮政公司将终止住宅邮件投递,并开始把13个社区约13.6万个地址转换为社区邮箱,这是其在五年内逐步取消上门投递以减少亏损的第一步。(新浪财经)

仕佳光子:拟12.65亿元投建高速光芯片与器件开发及产业化项目

36氪获悉,仕佳光子公告,公司拟投资建设高速光芯片与器件开发及产业化项目。本项目投资总额约为12.65亿元,资金来源为公司自有及自筹资金,项目建设周期为2年,实施地点位于河南省鹤壁市。主要内容涵盖土地厂房及生产线建设、设备购置等。本次投资旨在把握行业发展机遇,扩大核心产品规模化生产能力,强化技术优势与市场竞争力,完善公司在光通信领域的产业布局。该事项已经董事会审议通过,尚需提交公司股东会审议。本次投资不构成关联交易,也不构成重大资产重组。

国信证券:2025年净利润110.73亿元,同比增长34.76%

36氪获悉,国信证券发布2025年业绩报告。报告显示,期内实现营业收入241.43亿元,同比增长28.21%;归属于上市公司股东的净利润为110.73亿元,同比增长34.76%。公司拟向全体股东每10股派发现金红利3.50元(含税),不进行送股或以公积金转增股本。此外,公司已在2026年2月实施2025年前三季度分红派息,向全体股东每10股派发现金红利1.00元(含税)。本报告期公司合计向全体股东每10股派发现金红利4.50元(含税)。

盛新锂能:董事及高管拟合计减持不超0.091%股份

36氪获悉,盛新锂能公告,董事长周祎、董事兼总经理邓伟军等7名董事及高级管理人员计划自公告披露之日起15个交易日后的3个月内,以集中竞价或大宗交易方式减持公司股份合计不超过79.51万股,占公司总股本比例0.091%。减持原因为个人财务安排,股份来源为2021-2024年期间解锁的股权激励限制性股票。

韵达股份:3月快递服务业务收入45.9亿元,同比增长4.08%

36氪获悉,韵达股份公告,3月公司实现快递服务业务收入45.90亿元,同比增长4.08%;完成业务量21.42亿票,同比下降4.93%;快递服务单票收入2.14元,同比增长9.18%。上述数据未经审计,可能与定期报告数据存在差异,仅供投资者阶段性参考,相关数据以公司定期报告为准。

问界加入逸安启,与宝马、奔驰三方各持有33.3%股份

36氪获悉,今日,问界正式加入由宝马与梅赛德斯-奔驰创立的超充合资公司逸安启,三家各持有合资公司33.3%的股份。宝马、问界与梅赛德斯-奔驰将携手推进在中国的豪华超充网络建设。依据合作协议,问界车主将拥有与宝马、奔驰车主同等的充电权益。

藏格矿业:一季度净利润15.74亿元,同比增长110.6%

36氪获悉,藏格矿业发布2026年第一季度财报。报告显示,2026年第一季度实现营业收入7.16亿元,同比增长29.61%;归属于上市公司股东的净利润为15.74亿元,同比增长110.60%。业绩变动主要系权益法核算的投资收益显著增加所致。
❌