iview组件库的树型表格_组件库的摇树问题

文章探讨了在使用iview组件库时,树型表格所遇到的问题,特别是关于摇树(Tree Shaking)在组件库中的应用和挑战。原文链接为https://medium.com/sainsburys-engineering/tree-shaking-problems-with-component-libraries-e1afe683fd29。
摘要由CSDN通过智能技术生成

iview组件库的树型表格

It’s not magic, sadly.

不幸的是,这不是魔术。

Whether you like it or not, Webpack is endemic to modern front end applications. It’s an incredible tool, building on the legacy of Grunt, Gulp and others, and making the tools and progress that fuelled the JavaScript renaissance — like Babel and ES6 — accessible to everyone “to just build apps”.

无论您是否喜欢, Webpack都是现代前端应用程序所特有的。 这是一个令人难以置信的工具,它建立在Grunt,Gulp等人的遗产的基础上,并使所有人都可以使用“仅构建应用程序”的工具和进步来推动JavaScript复兴,例如Babel和ES6。

But as we bundle more and more dependencies into our “rich” applications, it’s become easy to lose sight of the sheer sizes we’re shipping to client devices. This is often hand-waved away these days, as devices, connections and storage continue to grow faster than ever before — but we mustn’t forget the experience penalties for large bundles that still exist on lower end devices or slower connections.

但是,随着我们将越来越多的依赖项绑定到我们的“丰富”应用程序中,就很容易忽略了我们要交付给客户端设备的庞大规模。 如今,随着设备,连接和存储的增长比以往任何时候都快,这常常被人们挥之不去。但是,我们不能忘记,对于在低端设备或连接速度较慢的情况下仍然存在的大型捆绑包,我们会遭受惩罚。

Fortunately, as our bundlers evolved, as did the tools and techniques for reducing bundle sizes. Uglify was replaced with Uglify-es, and then forked and changed into Terser. As we move towards ES Modules, and enjoy support for them in modern browsers, technology like tree-shaking can ensure only the code we use, is the code we bundle. This is essential when dipping into kitchen-sink frameworks like React-Bootstrap and the inevitable corporate component library.

幸运的是,随着捆扎机的发展,减少捆扎尺寸的工具和技术也在不断发展。 将Uglify替换为Uglify-es ,然后分叉并更改为Terser 。 随着我们朝着ES模块迈进,并在现代浏览器中享受对它们的支持,诸如摇树之类的技术可以确保只有我们使用的代码才是我们捆绑的代码。 当浸入诸如React-Bootstrap之类的厨房接收器框架和不可避免的公司组件库时,这是必不可少的。

And it’s here, in the cosy, progressed world of low-config tools, breezily piecing together websites from a company library of components and npm, that we find ourselves shot in the foot and realising: it’s not magic, sadly.

正是在这里,在低配置工具的舒适,进步的世界中,轻松地将公司组件库和npm的网站拼凑在一起,我们发现自己步履蹒跚并意识到: 这不是魔术,可悲的是

TL; DR (TL;DR)

  • Tree-shaking isn’t magic, and much like the garbage collector, you need to understand a little of what it’s doing to get the best from it.

    摇树并不是魔术,就像垃圾收集器一样,您需要了解一些有关如何从中获取最大收益的方法。
  • If you’re publishing a component library, offer an ES Module build — and avoid rolling all your modules into a single file.

    如果要发布组件库,请提供ES模块构建-避免将所有模块滚动到一个文件中。
  • PropTypes, defaultProps and other static assignments, as well as HOCs that may include side effects, will prevent your components from being tree-shaken.

    PropTypesdefaultProps和其他静态分配以及可能包含副作用的PropTypes都将防止组件摇晃。

If you follow the tree-shaking guide in Webpacks docs, it will take you on a whistle-stop tour of making your application ready to only bundle code that’s actually used. The four big points from that guide are:

如果您遵循Webpacks docs中的“摇摇欲坠”指南 ,它将带您全面了解如何使您的应用程序准备好只捆绑实际使用的代码。 该指南的四大重点是:

* Use ES2015 module syntax (i.e. import and export).

*使用ES2015模块语法(即importexport )。

* Ensure no compilers transform your ES2015 module syntax into CommonJS modules (this is the default behavior of the popular Babel preset @babel/preset-env — see the documentation for more details).

*确保没有编译器将您的ES2015模块语法转换为CommonJS模块(这是流行的Babel预设@ babel / preset-env的默认行为-有关更多详细信息,请参阅文档 )。

* Add a "sideEffects" property to your project's package.json file.

*在项目的package.json文件中添加一个"sideEffects"属性。

* Use the production mode configuration option to enable various optimizations including minification and tree shaking.https://webpack.js.org/guides/tree-shaking/#conclusion

*使用production mode配置选项来启用各种优化,包括缩小和摇树。 https://webpack.js.org/guides/tree-shaking/#conclusion

I knew that the application I was building checked all of these, and that the component library did too — I could see it in plain code in their package bundle. However, I was still bundling the entire component library — what was going on?

我知道我正在构建的应用程序检查了所有这些内容,并且组件库也做了检查-我可以在其软件包捆绑中的纯代码中看到它。 但是,我仍在捆绑整个组件库-这是怎么回事?

PropTypes,组件和终结器 (PropTypes, Components & Terser)

Under the hood, Webpack does part of tree-shaking itself, and leaves the remaining dead-code elimination and compression to a minifier, in this case: Terser.

在后台,Webpack本身会进行部分树状摇动,并将剩余的死代码消除和压缩留给压缩程序,在本例中为Terser。

Minifiers, like Terser, are fantastic, powerful and complicated tools. They can take enormous, branching, heavily nested JavaScript files, and whittle them down to smaller, optimised versions — with no runtime behaviour changes. However, to achieve this feat while not breaking your code, they need to have a degree of safety to what they can and cannot remove. As before — they’re not magic, sadly — and they won’t remove code that could have a side effect that isn’t obvious till runtime.

缩小程序 (如Terser )是出色,强大而复杂的工具。 它们可以获取庞大的,分支的,高度嵌套JavaScript文件,并将它们缩减为更小的优化版本-而无需更改运行时行为。 但是,要在不破坏您的代码的情况下实现这一壮举,他们需要对可以删除和不能删除的内容具有一定的安全性。 和以前一样-不幸的是,它们并不是魔术,并且不会删除可能在运行时不明显的副作用的代码。

One of these potential side effects nestles in a very common language feature: dot assignment. As getters and setters for properties can be functions, which themselves can have side effects, it’s not safe to assume that a simple assignment can be removed if the left hand side object is not actually used.

这些潜在的副作用之一位于一种非常常见的语言功能中:点分配。 由于属性的getter和setter可以是函数,而函数本身也可能具有副作用,因此,如果实际上未使用左侧对象,则假定可以删除一个简单的赋值是不安全的。

const cat = {}Object.defineProperty(
set() {
throw new Error('No!')
}
})cat.name = 'Catrick'

While this may look contrived, Terser isn’t here to judge your approach to solving problems — and it will leave this code in place, unsure if removing it will break runtime behaviour. That said, this example was unlikely and contrived, but one that’s not so, and that we use frequently in our React components, is propTypes.

尽管这看起来可能是人为的,但Terser并不是在这里判断您解决问题的方法-它将使该代码保留在原处,不确定删除它是否会破坏运行时行为。 这就是说,本例中不可能和做作,而是一个不是这样了,我们在我们的React的组分经常使用,是propTypes

const MyComponent = ({ name }) => <h1>Hello {name}</h1>MyComponent.propTypes = {
name: PropTypes.string,
}MyComponent.defaultProps = {
name: 'Chris'
}

Here, we’ve made two static assignments to a function, MyComponent. Terser cannot tell if these assignments would cause a side effect, and therefore won’t remove them— and by extension, won’t remove the component itself — even if it’s completely unused.

在这里,我们对函数MyComponent进行了两个静态分配。 Terser无法确定这些分配是否会引起副作用,因此不会删除它们-且通过扩展,也不会删除组件本身-即使它完全没有使用。

If you try this yourself, you’ll find there’s a special case — a single assignment. If you only make a single static assignment to a function, Terser will correctly remove it all if unused. This is due to another compression trick Terser has:

如果您自己尝试此操作,则会发现有一种特殊情况-一项作业。 如果仅对函数进行单个静态分配,则Terser将在未使用时正确地将其全部删除。 这是由于Terser具有另一个压缩技巧:

var myFunction = () => {}
myFunction.foo = 'bar'// Gets compressed too;(o=()=>{}).foo="bar"// Which can be successfully removed
// But...var myFunction = () => {}
myFunction.foo = 'bar'
myFunction.bar = 'foo'// Gets a second assignment, and cannot be removed.o;(o=()=>{}).foo="bar",o.bar="foo"

为什么对象不会发生这种情况? (Why doesn’t this happen to objects?)

If you experiment with this in Terser, you might find that objects don’t suffer from multiple assignments changing their compression. This is due to hoist_props working with compression for objects — their multiple assignments get hoisted into a single object:

如果您在Terser中进行实验,您可能会发现对象不会因为更改其压缩而受到多次分配的困扰。 这是由于hoist_props对对象进行压缩-它们的多个分配被提升到一个对象中:

var myObject = {}
myObject.foo = 'bar'
myObject.bar = 'foo'// Becomeso;o={foo:"bar",bar:"foo"}

我们该如何解决? (How can we fix this?)

A way round this is to wrap your components in IIFEs. By wrapping them in this scope, Terser can know that, even with multiple assignments, the entire component is safe to remove if unused. However, this is very cumbersome — and brittle if forgotten.

一种解决方法是将组件包装在IIFE中 。 通过将它们包装在此范围内,Terser可以知道,即使有多个分配,如果不使用整个组件,也可以安全地删除它们。 但是,这非常麻烦-如果忘记的话,它会很脆弱。

Luckily, there’s another route. Earlier, one of the tips Webpack gave for ensuring your code could be tree-shaken, was to use ES Modules. However, it doesn’t go any further to say how best to use them. If you’re writing a component library, and you’re producing an ES Module build (which you should!), don’t bundle this into one file.

幸运的是,还有另一条路。 早先,Webpack提供的确保您的代码可以摇晃的技巧之一就是使用ES模块。 但是,再也没有说出如何最好地使用它们了。 如果您正在编写组件库,并且正在生成ES Module构建(您应该这样做),请不要将其捆绑到一个文件中。

var MyFirstComponent = function MyFirstComponent(props) {
  return /*#__PURE__*/React.createElement("div", props);
};


MyFirstComponent.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string
};


MyFirstComponent.defaultProps = {
  children: undefined,
  className: undefined
};


var MySecondComponent = function MySecondComponent(props) {
  return /*#__PURE__*/React.createElement("div", props);
};


MySecondComponent.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string
};


MySecondComponent.defaultProps = {
  children: undefined,
  className: undefined
};


export { MyFirstComponent, MySecondComponent };

By concatenating your modules together, even if they are ultimately exposed with export, you create a scope in which Terser cannot identify side-effect free assignments. Instead, publish your modules as separate files, joined with import and export. Bundlers consuming your library can then drop entire modules if they’re unused, drastically reducing your code.

通过将模块串联在一起,即使它们最终在export暴露出来,您也可以创建一个范围,在该范围内Terser无法识别无副作用的分配。 而是将模块作为单独的文件发布,并与importexport结合在一起。 占用您库的捆绑程序可以在未使用整个模块的情况下删除它们,从而极大地减少了您的代码。

export { default as MyFirstComponent } from './MyFirstComponent'
export { default as MySecondComponent } from './MySecondComponent'

Tools like Babel are great for transpiling entire folders of modules into ES6 code, while preserving the separate module files. Unfortunately, Rollup is less good at this — and will concatenate your modules together by default.

Babel之类的工具非常适合将模块的整个文件夹转换为ES6代码,同时保留单独的模块文件。 不幸的是, 汇总功能在这方面不太好-默认情况下会将模块串联在一起。

最后一件事:重组,高阶成分和纯度 (One Last Thing: Recompose, higher-order-components, and purity)

Libraries like recompose can make building components by composition much easier. However, using these functions can make it difficult for Terser to know if they’ll have side-effects, and if it can safely remove the component if unused.

recompose这样的库可以使按组成的构建组件更加容易。 但是,使用这些功能可能会使Terser很难知道它们是否会产生副作用,如果不使用它们也可以安全地删除该组件。

const MyComponent = ({ name }) => <h1>Hello {name}</h1>export default compose(...)(MyComponent)

Putting your components in different modules (files), and not bundling them together if you’re publishing a library, will help ease this — as the entire module can be dropped.

将您的组件放在不同的模块(文件)中,如果要发布库,则不要将它们捆绑在一起,这将有助于减轻压力-因为可以删除整个模块。

However, if you’re not able to put them in different files, or don’t want to, and you’re sure there’s no side-effect to your HOC, annotate it with /*#__PURE__*/. This tells Terser that it’s side-effect free, and if unused, can be safely removed.

但是,如果您无法将它们放入不同的文件中,或者不想将它们放入其他文件中,并且您确定HOC没有副作用,请使用/*#__PURE__*/对其进行注释。 这告诉Terser它没有副作用,并且如果没有使用,则可以安全地删除。

const MyComponent = ({ name }) => <h1>Hello {name}</h1>const myComposedComponent = /*#__PURE__*/compose(...)(MyComponent)

Sadly, an annotation like this doesn’t exist for assignments! However, annotations like this should be a last resort, for when you’re in a corner that Terser just can’t resolve. Favour separate modules, or marking a package as sideEffects: false over involved annotations.

可悲的是,这样的注释不存在分配! 但是,这样的注释应该是不得已的方法,因为当您身处Terser无法解决的角落时,请注意。 支持单独的模块,或将包标记为sideEffects: false对所涉及的注释为sideEffects: false

谢谢! (Thanks!)

Hopefully, this article has helped you slim down your imports with a component library, or understand a little more about the esoteric world that goes on behind the scenes in your bundler.

希望本文能够帮助您使用组件库来简化导入,或者进一步了解捆绑器中幕后发生的神秘世界。

Below are some references that helped me debug these issues, and provided valuable insight into the tool.

以下是一些有助于我调试这些问题的参考,并提供了对该工具的宝贵见解。

Remember, Tree-shaking isn’t magic, and much like the garbage collector and other parts of our ecosystem, it’ll generally serve you well, but you need to understand a little of what it’s doing to get the best from it.

请记住,摇树并不是魔术,就像垃圾收集器和我们生态系统的其他部分一样,它通常可以很好地为您服务,但是您需要了解一些有关如何从中获取最大收益的方法。

翻译自: https://medium.com/sainsburys-engineering/tree-shaking-problems-with-component-libraries-e1afe683fd29

iview组件库的树型表格

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
treegrid插件 当前选中的行: var config = { id: "tg1", width: "800", renderTo: "div1", headerAlign: "left", headerHeight: "30", dataAlign: "left", indentation: "20", folderOpenIcon: "images/folderOpen.gif", folderCloseIcon: "images/folderClose.gif", defaultLeafIcon: "images/defaultLeaf.gif", hoverRowBackground: "false", folderColumnIndex: "1", itemClick: "itemClickEvent", columns:[ {headerText: "", headerAlign: "center", dataAlign: "center", width: "20", handler: "customCheckBox"}, {headerText: "名称", dataField: "name", headerAlign: "center", handler: "customOrgName"}, {headerText: "拼音码", dataField: "code", headerAlign: "center", dataAlign: "center", width: "100"}, {headerText: "负责人", dataField: "assignee", headerAlign: "center", dataAlign: "center", width: "100"}, {headerText: "查看", headerAlign: "center", dataAlign: "center", width: "50", handler: "customLook"} ], data:[ {name: "城区分公司", code: "CQ", assignee: "", children:[ {name: "城区卡品分销中心"}, {name: "先锋服务厅", children:[ {name: "chlid1"}, {name: "chlid2"}, {name: "chlid3", children: [ {name: "chlid3-1"}, {name: "chlid3-2"}, {name: "chlid3-3"}, {name: "chlid3-4"} ]} ]}, {name: "半环服务厅"} ]}, {name: "清新分公司", code: "QX", assignee: "", children:[]}, {name: "英德分公司", code: "YD", assignee: "", children:[]}, {name: "佛冈分公司", code: "FG", assignee: "", children:[]} ] }; /* 单击数据行后触发该事件 id:行的id index:行的索引。 data:json格式的行数据对象。 */ function itemClickEvent(id, index, data){ window.location.href="ads"; } /* 通过指定的方法来自定义栏数据 */ function customCheckBox(row, col){ return ""; } function customOrgName(row, col){ var name = row[col.dataField] || ""; return name; } function customLook(row, col){ return "查看"; } //创建一个组件对象 var treeGrid = new TreeGrid(config); treeGrid.show(); /* 展开、关闭所有节点。 isOpen=Y表示展开,isOpen=N表示关闭 */ function expandAll(isOpen){ treeGrid.expandAll(isOpen); } /* 取得当前选中的行,方法返回TreeGridItem对象 */ function selectedItem(){ var treeGridItem = treeGrid.getSelectedItem(); if(treeGridItem!=null){ //获取数据行属性值 //alert(treeGridItem.id + ", " + treeGridItem.index + ", " + treeGridItem.data.name); //获取父数据行 var parent = treeGridItem.getParent(); if(parent!=null){ //jQuery("#currentRow").val(parent.data.name); } //获取子数据行集 var children = treeGridItem.getChildren(); if(children!=null && children.length>0){ jQuery("#currentRow").val(children[0].data.name); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值