十几年前使用了devexpress公司的delphi元件,功能很强。它们的html元件devextreme,功能表现类似,也行强。
devextreme和devextreme-react,我使用的是23.2.3版本。
官方推荐的用法,都是要经过build:
npx devextreme-cli new react-app app-name
cd app-name
npm run start
经过约12秒的build,出来的html中有一个bundle.js,大小为12.5M。
它的模式是MPA,用babel把react组件转换成了js代码。
如果我要做SPA,不要每次都build,如何做?
devextreme和devextrem-react提供了cjs(es5)和esm(es6)两套代码,但是react本身没有esm的代码版本,如果devextreme使用esm版本,还是要经过babel转成es5来使用。
我们用es5的cjs版本吧。
(1)首先要在浏览器实现一个require函数,我是用breq - npm来改的。
(2)后台如何提供模组加载,我用nodejs实现静态文件。
会遇到几个问题:
(1)引用的组件不是相对路径,不是.、..、/打头的。
如:
import {TabPanel,Item as TabPanelItem} from 'devextreme-react/tab-panel.js';
import {locale,loadMessages} from 'devextreme/localization.js';
require需要仿照import实现一个importMap,建立文件映射表,如:
{
"devextreme-react/tab-panel.js":'/devextreme-react/cjs/tab-panel.js',
"devextreme/localization.js":'/devextreme-react/cjs/localization.js',
}
但是devextreme组件文件有500个以上,用绝对路径加载的也有好几十个,如果一个个加到importMap中也挺累的。可以实现一个目录映射来一网打尽,如:
"devextreme/":"/devextreme/cjs/",
实现后,发现其实import的importMap也支持这样的目录映射,好多文章没讲。
(2)引用的组件没有扩展名,如:
import {TabPanel,Item as TabPanelItem} from 'devextreme-react/tab-panel';
import {locale,loadMessages} from 'devextreme/localization';
var _file_saver = require("./exporter/file_saver");
var _image_creator = require("./exporter/image_creator");
var _svg_creator = require("./exporter/svg_creator");
var _type = require("./core/utils/type");
var _deferred = require("./core/utils/deferred");
var _pdf_creator = require("./exporter/pdf_creator");
这需要后台的static函数支持这种检查,看看加上.js、.cjs扩展名是否存在此文件。
(3)引用的组件是个目录。
后台的static要尝试查找此目录下的index.js文件,如果没有index.js,看看有没有package.json文件,解析使用其中的main属性指向的文件。
组件是目录时,还导致一个额外的问题,浏览器发起者不知道这是个目录,以为是个文件,所以接下来再加载相对路径的组件时,就会导致路径错误,如:
let require('a/b/c'),实际是加载了/a/b/c/index.js,浏览器以为是来自/a/b/c.js,当前目录是/a/b,实际当前目录应该是/a/b/c,如果index.js中有一句require('../d.js'),浏览器就会解析为require('/a/d.js'),导致找不到文件,实际应该是a/b/d.js。
有两种方法解决:
a.后台的实际文件,返回到res的headers的location中,参考重定向的规范:http响应状态码(Header常见属性 — Location属性)_http location-CSDN博客。如:res.set('location',req.url);前台获得后,按location值设定当前目录。
b.在importMap中特殊配置一个映射,如:“a/b/c”:"/a/b/c/index.js"
(4)循环引用。就是一个引用文件还没解析执行完,又被其它文件引用到了。devextreme-react中发现2处,引用栈如下:
0: "/devextreme-react/cjs/core/component-base"
1: "/devextreme-react/cjs/core/template-manager"
2: "/devextreme-react/cjs/core/template-wrapper"
3: "/devextreme-react/cjs/core/component-base"
0: "/devextreme-react/cjs/core/component-base"
1: "/devextreme-react/cjs/core/template-manager"
2: "/devextreme-react/cjs/core/component-base"
devextreme中发现1处:
0: "/devextreme/cjs/ui/popup"
1: "/devextreme/cjs/ui/popup/ui.popup.full"
2: "/devextreme/cjs/ui/toolbar"
3: "/devextreme/cjs/ui/toolbar/ui.toolbar"
4: "/devextreme/cjs/ui/toolbar/strategy/toolbar.singleline"
5: "/devextreme/cjs/ui/toolbar/internal/ui.toolbar.menu"
6: "/devextreme/cjs/ui/popup"
为了避免循环引用的死循环栈溢出,require的cache需要在eval前就加入,不能在之后加入。
循环引用实际没有导致devextreme元件出bug,因为export的是一个object,加上js代码执行时的”Hoisting"(变量和函数提升),不马上使用require结果时没有问题。
如:\devextreme-react\cjs\core\template-wrapper.js
var component_base_1 = require("./component-base");
...
var TemplateWrapperComponent = function (_a) {
component_base_1 = require("./component-base");//add by mustapha
...
}
第1行代码不能删除,否则可能导致其它组件没有加载进来。TemplateWrapperComponent 中的那行其实也不用加,加了看起来更保险。
(5)require函数返回的module.exports如何处理default?
不要做任何处理,直接返回module.exports。
对于:文章来源:https://www.toymoban.com/news/detail-818092.html
import {A} from '/x.js';
A.name='shanghai';
import B from '/y.js';
B.name='chongqing';
export default {A,B};
export {A,B};
banel转换后,首先会把module.__esModule设置为true,对import B,会用_interopRequireDefault函数为非模组化元件准备default值,后面统一用y['default']赋值给B。文章来源地址https://www.toymoban.com/news/detail-818092.html
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "A", {
enumerable: true,
get: function get() {
return _x.A;
}
});
Object.defineProperty(exports, "B", {
enumerable: true,
get: function get() {
return _y["default"];
}
});
exports["default"] = void 0;
var _x = require("/x.js");
var _y = _interopRequireDefault(require("/y.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
_x.A.name = 'shanghai';
_y["default"].name = 'chongqing';
var _default = {
A: _x.A,
B: _y["default"]
};
exports["default"] = _default;
到了这里,关于浏览器require加载devextreme-react组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!