我有一个带有基本Three.js设置的角度应用程序。我使用Bazel构建并运行这个应用程序。在我尝试从OBJLoader2导入three/examples/jsm/loaders/OBJLoader2之前,一切都很好。
const module = await import('three/examples/jsm/loaders/OBJLoader2')
const loader = new module.OBJLoader2()上面的代码片段不适用于devserver。我在浏览器控制台中得到了这个错误:
GET http://localhost:4200/three/examples/jsm/loaders/OBJLoader2.js net::ERR_ABORTED 404 (Not Found)
Error: Script error for "three/examples/jsm/loaders/OBJLoader2"
at makeError (ts_scripts.js?v=03400874:175)
at HTMLScriptElement.onScriptError (ts_scripts.js?v=03400874:1745)因此,devserver无法找到导入的脚本。但是在生产中运行这个应用程序非常好。
最小再生产
只需运行yarn install,然后运行yarn dev (它会导致浏览器控制台@http://localhost:4200中的错误)。而不是yarn pwa @ http://localhost:8080工作得很好!
发布于 2020-10-11 23:44:40
最后一个答案是不完全正确的,因为它得到了下一个错误:TypeError: Cannot read property 'Objloader2' of undefined。我错过了它,因为我在开发控制台中查看了Network。但是不管怎么说,从服务器获取文件会返回200条信息,这是有意义的。
在那里发生的事情是,ts_devserver只期望UMD输入,但是我们的脚本是另一回事。所以,接下来我要做的就是通过npm_umd_bundle包装它
load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle")
npm_umd_bundle(
name = "objloader_umd",
package_name = "objloader",
entry_point = "@npm//:node_modules/three/examples/jsm/loaders/OBJLoader2.js",
package = "@npm//three",
)并将其作为脚本添加到ts_devserver中:
ts_devserver(
...,
scripts = [
...,
":objloader_umd",
],
)它给了我们什么?现在我们可以从人工创建的模块objloader中导入东西了!
await import('objloader')一般情况下,可能就是这样。但为了方便,我们再做一件事吧。我们已经有了用于rxjs深度导入的rxjs_shims.js。让我们以类似的方式再添加一个类似的脚本:
// three/examples/jsm/loaders/OBJLoader2 -> objloader
(function (factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
} else if (typeof define === 'function' && define.amd) {
define('three/examples/jsm/loaders/OBJLoader2', ['exports', 'objloader'], factory);
}
})(function (exports, objloader) {
'use strict';
Object.keys(objloader).forEach(function (key) {
exports[key] = objloader[key];
});
Object.defineProperty(exports, '__esModule', {value: true});
});它主要做的是将three/examples/jsm/loaders/OBJLoader2导入路径混叠到objloader,特别是对devserver。
因此,现在我们甚至不需要区分dev和prod构建,因为导入可以是相同的。不需要更改TS源代码!
发布于 2020-10-11 05:50:54
发布于 2020-10-11 21:00:48
所以,它试图得到http://localhost:4200/three/examples/jsm/loaders/OBJLoader2.js,却无法得到它。合乎道理。
第一个注意事项:如果将导入路径更改为
// @ts-ignore
await import('npm/node_modules/three/examples/jsm/loaders/OBJLoader2')效果很好!(绕开tsc需要忽略tsc)。您甚至不需要添加这些additional_root_paths或任何其他three-related字段。
第二个注意事项:如果我们将"npm/node_modules/three"添加到additional_root_paths并将导入修正为
// @ts-ignore
await import('examples/jsm/loaders/OBJLoader2')那它也能用。
但不幸的是,以类似的方式添加"npm/node_modules"并不能使原始导入工作.嗯。
因此,我不知道如何使这个导入在dev和prod中都能工作。但我可以提出一个解决办法!由于它是一个动态导入,所以可以使用类似于以下内容的方法:
let module;
if (isDev) {
// @ts-ignore
module = await import('npm/node_modules/three/examples/jsm/loaders/OBJLoader2')
} else {
module = await import('three/examples/jsm/loaders/OBJLoader2')
}我相信您已经知道如何区分dev和prod构建,并且可以自己形成isDev var ;)
另外,我听说把变量直接导入函数是不好的模式,因为它会破坏静态分析器。所以我不建议这么做:
const prefix = isDev ? 'npm/node_modules/' : '';
const module = await import(`${prefix}examples/jsm/loaders/OBJLoader2`)但是,不能完全确定是否为-else子句,因为import的参数仍然是静态的。
https://stackoverflow.com/questions/64209912
复制相似问题