V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tlerbao
V2EX  ›  程序员

前端:大家的 API 都是怎么导入导出的?

  •  1
     
  •   tlerbao · 270 天前 · 2262 次点击
    这是一个创建于 270 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Q:大家通常会选择下面哪种方案,指点一下理由;方案三中普通和箭头哪个更好?

    方案一

    // 分别导出
    export function funA(){}
    export function funB(){}
    export function funC(){}
    ...
    
    // 分别导入(按需)
    import {funA,funB,...} from 'XX'
    

    方案二

    // 分别导出 + 默认导出
    export function funA(){}
    export function funB(){}
    export function funC(){}
    ...
    
    export default { funA,funB,funC }
    
    // 可默认全部导入也可按需导入
    import {funA,funB} from 'XX'
    或
    import Api from 'xx'
    Api.funA...
    

    方案三

    // 直接默认导出全部
    export default {
        // 普通好?
        funA(){},
    
        // 箭头好?
        funB: () => {}
    }
    // 默认导入
    import Api from 'XXX'
    
    29 条回复    2024-02-20 09:21:48 +08:00
    webszy
        1
    webszy  
       270 天前
    方案 1 ,方便 tree-shaking
    webszy
        2
    webszy  
       270 天前
    再换成 箭头函数 更好

    @webszy
    tlerbao
        3
    tlerbao  
    OP
       270 天前
    @webszy #2 咱就是说假设 default 有 5 个接口,那么 import default 和只导入其中两个最后在打包体积上能差多啥哈哈。是不是中小项目完全不用考虑这个。
    codehz
        4
    codehz  
       270 天前
    不是可以 import * as Api from 'XXX' 吗
    webszy
        5
    webszy  
       270 天前
    @tlerbao 是的,不考虑优化你想怎么写就怎么写,既然你都问这个问题了,为什么不把优化做好,哪怕减少 0.1kb 对不对
    kneo
        6
    kneo  
       270 天前 via Android
    看具体情况。细粒度的函数肯定是一二。复杂点的业务有时候也用得着三。关键还是看实际怎么用的。要是用的别扭就再琢磨琢磨。
    XCFOX
        7
    XCFOX  
       270 天前
    几乎不用 export default ,因为 export default 不方便配合桶文件使用
    tlerbao
        8
    tlerbao  
    OP
       270 天前
    @kneo 在打包体积效率上有没有差很多
    IvanLi127
        9
    IvanLi127  
       270 天前
    从编码风格上来说,我选方案一,它看起来直观。方案二写起来怕漏掉,方案三缩进太多。
    tlerbao
        10
    tlerbao  
    OP
       270 天前
    @XCFOX 知识盲区,什么叫方便配合桶文件使用?
    tlerbao
        11
    tlerbao  
    OP
       270 天前
    @webszy #5 方案一你说换成箭头更好但是在 Webstorm 下,箭头函数没有类型注解,不如普通 function 来的直观
    不知道你能不能看见图,红线标注的普通函数默认有类型注解,不用悬停鼠标就知道返回什么类型哈
    webszy
        12
    webszy  
       270 天前
    @tlerbao 这个不清楚,我没碰到过这个问题,不用箭头函数也可以,箭头函数其实就是原型简化了一点,如果你有 babel 转译了其实还是 function
    XCFOX
        13
    XCFOX  
       270 天前
    桶文件本身不提供任何实现,而是重新导出其他模块的导出,一个典型的桶文件是: https://github.com/microsoft/TypeChat/blob/main/src/index.ts

    重新导出语句 export * from 'xxx' 是无法导出 export default 的。

    假如你有这样的文件结构:
    src/
    |-- utils/
    | |-- format.ts
    | |-- validate.ts
    | |-- index.ts
    并且在 src/utils/format 中使用 export default ,
    那么始终得使用 import '../utils/format' 导入。

    但是如果你使用桶文件,通常只需要 import '../utils'
    rabbbit
        14
    rabbbit  
       270 天前
    const funA = () => {}
    export {funA}

    import {funA} from "xxx"
    tlerbao
        15
    tlerbao  
    OP
       270 天前
    @XCFOX #13 那这样直接全部导入了,打包体积会不会很大哈。
    tlerbao
        16
    tlerbao  
    OP
       270 天前
    @rabbbit 我 11 楼的回复就有这个差别
    XCFOX
        17
    XCFOX  
       270 天前
    @tlerbao #15 不会,有 tree shaking
    tlerbao
        18
    tlerbao  
    OP
       270 天前
    @XCFOX #17 太专业,你说的 tree shaking ,是某些插件自动,还是 vite 什么的有这个,虽然全部导入了,但是用到什么打包什么?瞎猜
    iOCZS
        19
    iOCZS  
       270 天前
    @tlerbao esmoudle
    XCFOX
        20
    XCFOX  
       270 天前
    @tlerbao 使用 vite 的话,在 dev 模式下不会自动 tree shaking ,但在 build 时会 tree shaking ,使用 webpack 始终会自动 tree shaking
    tlerbao
        21
    tlerbao  
    OP
       269 天前
    @XCFOX #20 假设 import '../utils' 导入了 format.ts 的全部和 validate.ts 的全部,您的意思,假设我代码中只调用了 format 和 validate 中的部分,那么 vite 在打包的时候会自动 tree shaking ?是这个意思吗?
    lyxxxh2
        22
    lyxxxh2  
       269 天前
    几个接口 直接写
    十几个接口 方案 3
    二十几个接口 方案 1

    方案 2: 感觉有点无语 1 和 3 的缝合怪
    CLMan
        23
    CLMan  
       269 天前   ❤️ 2
    这个可以参考 google typescript style guidle ,只需要使用 1 ,不建议使用 2,3 ,也没有什么必须使用 2,3 的场景。

    至于上面说的桶文件,其实更多是基于兼容性和习惯( Deno 作者吐槽为设计错误),并不是说这种设计就是好的。通常情况下,仅限于包级别使用( src/index.js )。

    如果考虑浏览器兼容,需要 iife 模式(脚本模式),rollup 对 1,2 产生相同的结果,因此也不需要必须使用默认导出。

    我也不知道当初 es 是为啥设计默认导出,我一直以来猜测是为了兼容 iife 模式,一个库提供一个全局对象,避免污染 global 作用域。但没有证据能证明我的猜测。
    CLMan
        24
    CLMan  
       269 天前   ❤️ 1
    @CLMan 我翻了下 ECMAScript 的早期相关讨论,终于找到了一个相关文档: https://archives.ecma-international.org/2014/misc/2014misc6.html

    这个文档证明了我的以上猜测,默认导出设计的初衷就是为了兼容类似 jQuery 这样 ES6 之前的流行的 JS 使用模式(全局单例对象),也确实如文档所说,给当时的 JS 使用者以及后来的 JS/TS 使用者造成了混乱。

    这是典型的编程语言设计时因缺乏长远考虑,给后来的使用者带来困扰,后来的使用者还必须得考古才能理解其应用场景,了解语言的缺陷仅为了避免使用该缺陷是当代的编程语言学习者常常面临的情况。
    tlerbao
        25
    tlerbao  
    OP
       269 天前
    @CLMan #24 兄弟,太专业了吧
    SchneeHertz
        26
    SchneeHertz  
       269 天前
    function funA(){}
    function funB(){}
    function funC(){}
    ...

    export default { funA,funB,funC }

    import {funA,funB} from 'XX'
    // or
    import XX from 'XX'

    只是习惯
    mark2025
        27
    mark2025  
       269 天前
    1. 尽量避免同时使用具名导出和默认导出
    2. 推荐统一使用具名导出
    CLMan
        28
    CLMan  
       268 天前
    @CLMan 补充下,默认导出目前还是有一些应用场景:

    - 使用 JS/TS 作为配置文件,rollup,jest,vite 等框架的配置文件都是采用默认导出

    除了以上场景,一般情况下自己的代码都没有必须使用默认导出的必要。
    alleluya
        29
    alleluya  
       268 天前
    @CLMan 默认导出这个贺老吐槽过好多回 主要原因就是你回复里说的 语言设计时因缺乏长远考虑 导致后来使用时出现了混乱 和 nodejs 用 cjs 而不是 esm 也有关系吧我记得
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2799 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 15:34 · PVG 23:34 · LAX 07:34 · JFK 10:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.