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

麻烦前端大佬看看, THREE 项目重写

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

    麻烦前端大佬看看

    原来有一个 THREE.JS 项目是一个 index.html 直接包含了 three.min.js 和一堆 js 文件。 包含 three.min.js 之后,有了一个全局的 THREE 对象 后面那一堆 js 便对 THREE 这个对象增加了一系列的函数与变量,并且互相引用

    示例 EVALoader.js
    THREE.EVALoader = function(onLoad, url, options){
    	// todo something
    }
    
    THREE.AAA = function(){
        // todo something
    }
    
    THREE.BBB = function(){
        // todo something
    }
    

    打算用 node 改写, 我能想到的方法: 就是也导出一个对象 THREE ,然后每个 js 改写 THREE 的地方,直接引用这个对象并增加函数和变量

    这样可行吗?

    globals.js 文件
    
    import * as THREE from "three";
    window.THREE = THREE;
    export default THREE;
    
    EVALoader.js 文件
    
    import * as THREE from "globals"
    
    THREE.EVALoader = function(onLoad, url, options){
        // todo something
    }
    
    THREE.AAA = function(){
        // todo something
    }
    
    THREE.BBB = function(){
        // todo something
    }
    

    如果可行,其他文件直接从 globals 引入 THREE 就可以使用 EVALoader 这个函数?

    22 条回复    2023-09-04 22:38:45 +08:00
    okakuyang
        1
    okakuyang  
       236 天前 via iPhone
    你应该想说用 es6 模块的方式来写吧?不需要 window.three = three 吧
    johnman
        2
    johnman  
    OP
       236 天前
    @okakuyang 是。引用再导出就可以了吗?
    貌似原来的 THREE.Vector3 等方法就无法使用了?
    bhbhxy
        3
    bhbhxy  
       236 天前
    不建议用 window.xxx 来挂载全局对象,用模块化的方式,哪里需要就哪里导入,共享数据自己实现一个简易的 vuex
    okakuyang
        4
    okakuyang  
       236 天前 via iPhone
    import { vector3 } from “three”
    okakuyang
        5
    okakuyang  
       236 天前 via iPhone
    你要看你引入的版本是不是按模块导出的,如果不是,去找模块导出的版本,如果没有需要自己改导出
    johnman
        6
    johnman  
    OP
       236 天前
    @okakuyang

    我尝试理解一下,如果 THREE.JS 是按照模块导出的。

    我在文件 A 对 THREE 模块 import 之后,增加函数 C 和变量 D 。

    其他文件 B 再次 import THREE 模块之后,可以执行函数 C 和读取/修改 D ?
    kongkx
        7
    kongkx  
       236 天前 via iPhone
    import 不配 打包工具?
    tangchi695
        8
    tangchi695  
       236 天前
    threejs 本身就打包了 esm 的版本啊
    itbeihe
        9
    itbeihe  
       236 天前
    多看看官方文档啊,three.js 官方支持 import 导入的。
    另外扩展 three 方法看看这个: https://discourse.threejs.org/t/extending-three-objects-in-r121-module-version/20197/4
    ```
    import { Mesh } from 'three';

    // extending an existing function 覆盖已存在方法
    const originalRaycast = Mesh.prototype.raycast;
    Mesh.prototype.raycast = function(...args) {

    const result = originalRaycast.apply( this, args );

    // custom logic...

    return result;

    };

    // Or you can add an entirely new function like this 新增方法
    Mesh.prototype.customFunction = function() {};
    ```
    johnman
        10
    johnman  
    OP
       236 天前
    @itbeihe

    还是不太懂

    实际上我想对
    import * as THREE from 'three' 这个 THREE 添加新方法

    而非对
    import { Mesh } from 'three'; 中的 Mesh 添加新方法
    horizon
        11
    horizon  
       235 天前
    你为啥要给 THREE 添加新方法
    johnman
        12
    johnman  
    OP
       235 天前
    @horizon 因为原项目存在大量此类操作并且文件之间互相引用。希望可以尽量减少改动
    itbeihe
        13
    itbeihe  
       235 天前
    @johnman 是想这样么?

    ````
    //myThree.js

    import * as Three from 'three'

    console.log('start',Three);
    // Three 不可扩展,只能用新对象承接
    const newThree = {...Three}
    newThree.test = function(){
    console.log('test');
    }

    export const three = newThree
    ````

    ````
    // 调用处
    import {three} from "./src/myThree.js"

    three.test()

    ````
    jspatrick
        14
    jspatrick  
       235 天前
    1. `打算用 node 改写`,nodejs 是无浏览器环境的运行时,肯定不能这样改写,因为没有 window 对象,threejs 包内部也包含一些浏览器环境的变量和函数
    2. 猜测你是想用 import 写法,既然已经看到 import 了,不妨重新组织下代码,对 EVALoader 这样的东西统一放置到 loaders 文件夹,不要修改 threejs 导出的对象,使用 import 来导入 EVALoader 和上述的 AAA 、BBB
    3. 打包工具问题,如果是体量较大,要工程化,那么建议是上个打包工具的,好处是无脑 install threejs 就完了,倘若代码量不高,浏览器也是支持 script type=module 形式导入的,threejs 同样提供了对应格式的 min 包
    horizon
        15
    horizon  
       235 天前
    @johnman #12
    那你要看下原来添加的方法里用了啥啊,可以改成依赖注入的方式,把 THREE 当作参数传入到新方法内。
    这样可能比较简单?
    johnman
        16
    johnman  
    OP
       235 天前
    @kongkx webpack
    nsjs
        18
    nsjs  
       235 天前
    #13 13 楼的方法是对的
    johnman
        19
    johnman  
    OP
       235 天前
    @jspatrick EVALoader.js 只是其中一个文件示例。原来项目代码有很多 JS 文件,每个 JS 都在 THREE 对象上加了自己的私活,并且 JS 文件之间直接引用其他文件创建的 THREE.xxx 方法。不知道如何快捷处理这种问题
    nsjs
        20
    nsjs  
       235 天前
    @johnman 你这个问题和 node 完全没有关系,就是 js 的模块封装问题
    就按 13 楼的方法就可以了。three.js 相当于一个 base module ,其它的如 EVALoader 都是 injector module ,你写一个自己的重导出的 module 就行了,如 my_three.js
    ```js
    import base module

    // 导入所有注入
    import EVALoader module
    import A module
    import B module
    ...
    import Z module

    // 导出
    export default xxx
    ```
    kongkx
        21
    kongkx  
       235 天前 via iPhone
    @johnman #17 建议多看看 three.js 的文档,以及示例。 估计有不少是 官方 addon
    johnman
        22
    johnman  
    OP
       235 天前
    @nsjs
    用了最土的办法

    globals.js
    import * as MYTHREE from "three";

    global.THREE = MYTHREE;
    global.EVA= EVA;

    console.log("start THREE", global.THREE);
    console.log("start THREE", global.EVA);

    export default MYTHREE;

    在 main.js 里面 import 了
    globals/EVALoader/EVAOptions/EVAPreviews....等等一大堆相互注入依赖的 js ,就搞定了。

    然后在全局暴露了 THREE 和 EVA
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2850 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 07:02 · PVG 15:02 · LAX 00:02 · JFK 03:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.