From Webpack:
A "side effect" is defined as code that performs a special behavior when imported, other than exposing one or more exports. An example of this are polyfills, which affect the global scope and usually do not provide an export.
@microsoft/fast-components and @microsoft/fast-components-msft both have side-effect imports. Importing any of the classes defined using @customElement from either of these packages registers the custom element with the UA's custom element registry. If I'm not mistaken, this is a text-book side effect and should be enumerated as such.
On the bright side, we can enumerate side-effect files in the package.json. Doing so should hopfully (I have not verified this) does prevent anyone importing a component from having to express the imported class:
import { FASTButton } from "@microsoft/fast-components";
// FASTButton doesn't declare itself as having side effects so tree-shaking
// algorithms think it is safe to remove without this statement
FASTButton;
Did some investigation on this. If the sideEffects property is properly enumerated by the package.json, then importing the Web Component implementation is sufficient; no need to express the import to circumvent tree-shaking:
{
"name": "@microsoft/fast-components",
"sideEffects": [ "./dist/esm/index.js", "./dist/esm/anchor/index.js"]
}
import { FASTButton } from "@microsoft/fast-components";
// No need to express a reference to the import to trick tree-shaking
// FASTButton;
The problem with the above is it could get difficult to maintain; new components get added and the package.json update is missed. I'd like to propose that we move all of the component definitions into a sub-directory in src/custom-elements. This is where all the custom element registration would happen. Utilities and other code that should be tree-shaken can be defined outside of that dir.
/src
- /custom-elements
- - /anchor
- - /button
...
- /utilities
With the above, a simple globbing pattern can be implemented for "sideEffects" and additions / removals won't be missed:
{
"sideEffects": ["./dist/esm/index.js", "./dist/esm/custom-elements/**/index.js"]
}
When you have ./dist/esm/index.js does that not also include ./dist/esm/custom-elements/**/index.js since the ./dist/esm/index.js should also export the custom elements?
I had the same question as @janechu
I might only argue for calling the folder elements to be a bit shorter in terms of path. No real strong opinion though.
In my testing that ./dist/esm/index.js file needs to be enumerated. Only enumerating the files exporting custom elements resulted in unintentional tree-shaking when custom elements were imported from the package main: import { FASTAnchor } from "@microsoft/fast-components"; // effectively "@microsoft/fast-components/dist/esm/index.js"
Interesting, well I'm in favor of the implementation. We may wish to alert our contributors on discord so they are aware things are moving.
I had the same question as @janechu
I might only argue for calling the folderelementsto be a bit shorter in terms of path. No real strong opinion though.
While technically these are the "custom elements", we refer to what is being exported (the custom elements) as "components" everywhere. I'm partial to keeping that language for the folder structure. It could be confusing to have two different terminologies present and someone may wonder if there is an intentional reason for it. Technically I think we're still talking about components. I agree that the implementation is that these are "custom elements" and "elements", but from a packaging perspective components makes a bit more sense for the folder name.
I can get on that train. Sounds good to me.
I'm easy on the name - "components" is fine by me.
Ship it!
It appears this doesn't work how I thought it would. I can get the behavior we're looking for with the above described approach in a trivial prototype project, but configuring the components package in the same way results in none of the components being tree shaken.
I'm still not sure why the behavior is different but I'm going to table this for the time being.
Closing this in favor of the provider approach.
Most helpful comment
In my testing that
./dist/esm/index.jsfile needs to be enumerated. Only enumerating the files exporting custom elements resulted in unintentional tree-shaking when custom elements were imported from the package main:import { FASTAnchor } from "@microsoft/fast-components"; // effectively "@microsoft/fast-components/dist/esm/index.js"