rollupjs avoid duplicated functions with multi files - rollup

I'm trying to pack all the common libraries to be used with multiple projects without an actual entry files. Thus I need all the functions to be included in the bundle
Thus I'm trying to achieve that using #rollup/plugin-multi-entry pointing to all the files inside the directory
The problem I'm facing currently is that, some of the files extends each other, when packed, the extended function is duplicated multiple times with the name $n and so on, is it possible to make rollup not duplicate those extended functions?
Thanks

Bundling libraries inside a vendor file is now considered an anti-pattern since you will neglect the benefits of three-shaking. It will also come with worse caching since every time some lib changes the cache of the whole vendor will be invalidated and, finally, you won't benefit from http2 multiplexing that much.
If you still want to do it, in order to give them reliable names (and avoid naming conflicts) it is much easier to do it manually:
// vendor.js
import * as lib1 from 'lib1';
import * as lib2 from 'lib2';
export {lib1, lib2}
The previous module, when used as entry point, will result in exporting all exports from both libraries under its respective namespaces, and rollup will internally handle dependencies between libs correctly.
Edit: if you can bundle the libraries along with the project and not in a different process you can do it like so:
// rollup.config.js
const libs = ['lib1', 'lib2'];
{
input: 'index.js',
manualChunks: {
vendor: libs.map((lib) => require.resolve(lib))
},
// ...
}

Related

Best practice for NPM package with es6 modules - bundle or not

Writing an NPM package containing es6 modules, is it best practice to keep the source files separate
package.json
esm
index.js
Content1
Content1A.js
Content1A.js.map
Content1B.js
Content1B.js.map
Content2
Content2A.js
Content2A.js.map
Content2B.js
Content2B.js.map
with index.js referencing contents in subfolders, or is it better practice to bundle it into one file
package.json
esm
contents.js
contents.js.map
Seems the first method has an advantage with CommonJS modules since it gives a consumer possibility to import directly from the source and thus skip unused imports from index.js (since CommonJS modules are not tree-shakeable) but with es6 modules, this argument disappears.
Different bundlers might be capable of different things. The rest of this answer refers to Webpack which, being one of the most common bundlers, should influence decisions in this area.
The most important factor governing the decision about whether to bundle your library or not should be related to tree-shaking. No other important aspects come to mind for me.
Parameters affecting tree-shaking in Webpack
sideEffects: false
Setting in package.json that indicates whether modules in the package have side effects which needs to be executed when the module is imported but not consumed. Setting it to false indicates that no modules have side effects. May also be set to a list of modules which have side effects and other more complex values. Default seem to be true indicating that all modules have side effects.
This parameters plays a large role when using an entrypoint index in your package, from which all package exports are re-exported. Sparse imports from this index could easily cause your entire package to be bundled if this setting is not correct.
optimization.usedExports: true
Setting in webpack.config.js indicating to Webpack that all exports that are not used may be excluded. This activates a heuristic used by Terser to remove unused code inside a module. Is set to true by default.
In toy scenarios, this setting might seem efficient enough and the sideEffects flag might not seem to play a big role. This is not the case in real scenarios with more complex code where it is harder for this heuristic to do a good job.
/*#__PURE__*/
Annotation to be used before statements (such as functions) to indicate that they can be excluded if not explicitly used. These annotations also play a part in the heuristic used by Terser to remove unused code inside a module.
Conclusion
To allow your consumers to benefit the most from tree-shaking, it seems advisable to not bundle your es6 npm package and instead let the separate input modules remain separate so that the sideEffects setting in package.json may result in the consumer bundler to prune as many unused modules as possible. Rely on optimization.usedExports inside modules, evaluate bundle content and add /*#__PURE__*/ annotations where you think it could make a big difference. If everything is bundled in the same file, the sideEffects flag in package.json can't do the main part of the job as everything is in the same module and subsequently we have to rely on a lot of additional /*#__PURE__*/ annotations and heuristics in the consumer bundler to make tree-shaking as efficient as possible, which requires more from you (in terms of annotations) and does not come with any particular advantage. Remember to build your package in production mode as optimizations are not always active otherwise.
Source
https://webpack.js.org/guides/tree-shaking/
Own experiments

CMake: How to tell where transitive dependency is coming from?

I'm in the process of rewriting a legacy CMake setup to use modern features like automatic dependency propagation. (i.e. using things like target_include_directories(<target> PUBLIC <dir>) instead of include_directories(<dir>).) Currently, we manually handle all project dependency information by setting a bunch of global directory properties.
In my testing, I've found a few examples where a target in the new build will link to a library that the old build would not. I'm not linking to it explicitly, so I know this is coming from the target's dependencies, but in order to find which one(s) I have to recursively look through all of the project's CMakeLists.txts, following up the dependency hierarchy until I find one that pulls in the library in question. We have dozens of libraries so this is not a trivial process.
Does CMake provide any way to see, for each target, which of its dependencies were added explicitly, and which ones were propagated through transitive dependencies?
It looks like the --graphviz output does show this distinction, so clearly CMake knows the context internally. However, I'd like to write a tree-like script to show dependency information on the command line, and parsing Graphviz files sounds like both a nightmare and a hack.
As far as I can tell, cmake-file-api does not include this information. I thought the codemodel/target/dependencies field might work, but it lists both local and transitive dependencies mixed together. And the backtrace field of each dependency only ties back to the add_executable/add_library call for the current target.
You can parse dot file generated by graphviz and extract details which you want. Below is sample python script to do that.
import pydot
import sys
graph = pydot.graph_from_dot_file(sys.argv[1])
result = {}
for g in graph:
# print(g)
for node in g.get_node_list():
if node.get("label") != None:
result[node.get("label")] = []
for edge in g.get_edges():
result[g.get_node(edge.get_source())[0].get("label")].append(g.get_node(edge.get_destination())[0].get("label"))
for r in result:
print(r+":"+",".join(result[r]))
You can also add this script to run from cmake as custom target, so you can call it from you build system. You can find sample cmake project here

Webpack 4 referencing npm vendor scripts

I'm trying to get my head around Webpack 4 for a medium-to-large scale (MVC) website.
For the solution, I want to use the following, base vendor scripts/styles:
jQuery vLatest minified version
Bootstrap, but only the grid, no javascript or anything else
The site consists on several templates different from each other. Some might have an image gallery where I want to use Owl Carousel vLatest and so on, so forth.
As I've understood, the vendor bundle should only contain the scripts/styles that is used across the entire site, so i.e., the Owl Carousel script/styles should not be a part of the vendor scripts since it's only used for one, maybe two specific templates.
I've installed jQuery and Bootstrap via npm so they're in the node_modules folder. Question is: how do I tell Webpack to use the minified version of jQuery in the vendor bundle? And how do I tell it to use only the grid component from Bootstrap? And what about the other third party scripts/styles, should they be included as their own entry?
My webpack.config.js entry file looks like this:
entry: {
'mysite.bundle.css': './scripts/webpack-entries/mysite.styles.js',
'mysite.bundle.js': glob.sync('./scripts/mysite/*.js'),
'vendor.bundle.js': [
'./node_modules/jquery/dist/jquery.min.js'
],
'vendor.bundle.css': [
'./node_modules/bootstrap/scss/bootstrap-grid.scss'
],
}
What feels weird about this is, that I could just aswell reference the jquery.min.js directly on my view and import bootstrap-grid.scss directly in my .scss files. Same could be said with the Owl carousel (and other vendor scripts)
Also, if I just do this: 'vendor.bundle.js': ['jquery'] the entire non-minified jQuery library is loaded rather than the minified version.
How exactly do you work with Webpack and NPM this way? :-)
Thanks in advance.
You can use { resolve } to configure aliases:
{
resolve: {
alias: {
'jquery': require.resolve('jquery/jquery.min.js')
}
}
}
However, I would caution first to focus on getting a viable build that's suitable for development and then enhance the configuration as needed to optimize for production. For example, during development you want to include all the sources with their entirety with good source maps. When you get to the point of publishing, use something like Environment Variables to introduce a flag that will enforce the necessary configuration.
No, it's not necessary to create entry points for particular vendor sources. This is reminiscent of the past practices. You should create individual entry points to logically split your large codebase into distinct bundles, like: the public web, the administrative application, the customer application, should you have the need to do so.
Also, don't spend too much time creating entrypoints to group vendor sources and such. Write your modules as you would, from the perspective of a developer, require from them what they depend on and then use webpack { optimize.minimizer }, other minification plugins and it's dependency graph heuristics to create necessary chunks using { optimize.splitChunks }.
Short answer is, and this has been true for webpack for a long time: do not change the way you write and organize sources to satisfy webpack. It's polished and sophisticated enough that it will accommodate to your style of authoring.

CMake: how to install lots of static files, but only when necessary?

Preface: I'm new to cmake and only have a barely-passing knowledge of how it works, so this may not be as hard as it looks to me. :-)
For various "legacy" reasons, I'm using cmake 2.8.12, and I have a large complicated project that I did not create, but now I'm trying to figure out how to make it build faster. In the top-level CMakeLists.txt file that drives everything, there are lots of targets defined for the app build and other things, and at the end it has something like "include(StaticResources)".
StaticResources.cmake defines (and at the end, calls) a function that just iterates over a ton of dirs with static files and installs each of those dirs to the output dir, as well as installing a few explicitly enumerate files, some of which are renamed.
The problem I'm trying to eliminate is that even if a build does nothing at all, this function takes many seconds as cmake goes through and visits each dir/file to see if it needs to be copied. I'm trying to figure out how to structure this so that it doesn't even look at that stuff if nothing has changed.
Any ideas? Things I have thought of trying (but am not sure how):
- possibly make that StaticResources function depend on the main app target in some way such that it only runs when the main app has to be built (this isn't ideal, of course, because lots things can change that app without requiring resources to be deployed)
- having a StaticResources "build" target that computes a hash of the state of all of these static resources files and writes it to an output file only if something is changed, then having this static resources function install that target with custom code that actually installs the static files. It seems like this would make sure that the install is only considered if/when the resources actually change, but I'm not sure if cmake will allow me to "install(StaticResources "

Dojo custom build: which files to deploy

First, we're new to Dojo and are free do things the "new" way, so I'm mostly ignoring the pre-1.7 sections of the documentation. Still, I'm coming up confused when comparing various articles, documents, and sample scripts.
The bottom line is that I can't find a straightforward write-up on how to create and deploy a custom build for Dojo. Most specifically, which .js and .css files we need to deploy. There's a lot of documentation on creating a build, but none I've found on deploying.
I eventually gathered that building everything into a single dojo.js is a reasonable practice for mobile, and that I simply have to extract that one file out of the build directories and deploy it to my server, but then I get missing CSS references, and it doesn't seem like trial-and-error is the correct way to resolve those.
Here's our specific, current case:
<script type="text/javascript">
require(
// deviceTheme to auto-detect device styles
[
"dojox/mobile",
"dojox/mobile/parser",
"dojox/mobile/deviceTheme"
]);
</script>
Here's the build profile:
dependencies = {
stripConsole: "normal",
layers: [
{
name: "dojo.js",
customBase: true, // prevent automatic inclusion of dojo/main
dependencies: [
"dojox.mobile.parser",
"dojox.mobile",
"dojox.mobile.deviceTheme"
]
}
],
prefixes: [
[ "dijit", "../dijit" ], // example included; not clear why
[ "dojox", "../dojox" ]
]
}
(Executed by the dojo-release-1.7.2-src\dojox\mobile\build\build.bat script.)
So I guess the specific questions are:
Which CSS files do I deploy for this case?
How do I know in general which files, including CSS files, to deploy?
Is there a good, current tutorial that I'm missing?
Are the existing scripts up-to-date? For example, why does mobile-all.profile.js use dependencies= instead of the profile= that the 1.7 build tutorial describes?
Which CSS files do I deploy for this case?
This is conditional, if a page uses a specific module and it has its own css-rules, include them.
This is not the way, but starting out with dojo.css (base, reset), dijit.css (base, layouts and more), nihilo.css (example theme) and android.css (example theme) would make a good foundation
If you want to use a theme, include the 'basename', e.g. dojox/mobile/themes/iphone/iphone.css
If for instance iphone.css does not '#import' some exotic widget you use, include the css which is delivered by the widget itself (as example, dojox/widget/ColorPicker/ColorPicker.css). Docs for each widget _should make not of this.
How do I know in general which files, including CSS files, to deploy?
There is no harm in uploading all files, the loader will decide which to get from cached-build, which to leave alone and what to download during runtime.
deploy everything.. when you build a 'action=release' all files are minified within the prefixes defined dojo (defaults, allways), dijit, dojox and any packages you add.
the build results in optimized toolkit-tree, deploy all or you might face a situation where a conditional include (Toggler.js for instance, or acme.js selector incl etc) is missing.
Is there a good, current tutorial that I'm missing?
By 'thumbrule', any 1.6+ docs are stable, but they mostly say the same. As you start a profile, it may get a bit trial and error (the sequence of inline-html inclusion of script files is of outmost importance). What you posted looks good, though think about if customBase:true is nescessary.
Make sure you have seen this for versions 1.6-1.7 and version 1.8
Are the existing scripts up-to-date? For example, why does mobile-all.profile.js use dependencies= instead of the profile= that the 1.7 build tutorial describes?
You can use the existing ones, out the box. The builder however is changing, moving up against the much debated 2.0 release. For now, the new schemes are allowed as well as the regular ones. But in fact the variable name can be foo or bar, only the variable's value is put to use. The file must 'return' a single object.
As i understood, the reason is that CommonJS Packages/1.0 is the new bible for AMD and builder 1.7+. It has allways been the 'thumb' scheme the package hierachy has followed however - but the syntax will most likely get more and more strict the closer we move to 2.0. (see if you can hook up with snover on #dojo # irc.freenode.org)