How do I load web-components with webpack - javascript

I'm using webpack 4 with elm and trying to bring in leaflet-map as a web-component. (This is desirable because elm has a virtual dom so mixing with standard JS tends to cause a fight over the controlled elements, it also reduces the usage of ports to talk to leaflet). However I'm struggling to configure webpack in such a fashion it recognises the import.
The package in question https://github.com/leaflet-extras/leaflet-map is a bower package and pretty much expects to be installed by bower, (otherwise it can't recognise polymer) so both the webpack-webcomponent-loader and polymer-loader packages seem to be ineffectual.
What I need to do is configure webpack to recognise a require("bower_components/leaflet_map/leaflet_map.html") or an <link import="bower_components/leaflet_map/leaflet_map.html"> as a web component and import the relevant bundle, but this is outside of my src directory.
How can I configure webpack to parse and bundle this html file into my app? And how should I be referencing it?

Related

Including/bundling dependencies in npm library with webpack

I've used webpack for a few single page apps and am now trying to build an npm library to be used by some of those apps (and anyone else who might find it useful.)
I understand that peerDependencies in package.json and externals in the webpack config go together. If I'm writing an AngularJS plugin, I don't bundle angular, because the consumer should already have it installed and we want to work with whatever version they're using.
Where I'm confused is on how to include another library I don't expect the consumer to have. If I list it in dependencies and import it and don't include it in externals, webpack seems to bundle the other library with my code. I don't think this is what I want.
If I list it in dependencies and do include it in externals, it seems not to be available in the consumer unless I explicitly include it in the consumer, e.g. a script tag pointing to a CDN. It acts like a peerDependency, even though it isn't.
Is it possible to have have my library's dependencies installed by npm in the consumer app and available at runtime without a) bundling the dependency into my library or b) forcing consumers of the library to explicitly load an obscure package?

How to prevent module coupling in very large webpack project?

I am working on a very large javascript framework (approx 1000 javascript files). Which is currently built using Webpack. I have identified that some parts of the app are core modules, and other parts are components that use the core.
I would like to prevent developers from coupling the non-core modules and the core modules. And generally prevent inter module coupling outside of what the module exports.
When I say modules, I am not referring to a single js file which is an es6 module. Rather I am referring to a folder that contains React components, Reducers, Sagas et. all that all together constitue a logical module.
What I want is that each "module" could be a folder containing an index.js file at it's root which exports what that module wants to expose. Somehow I want to prevent other modules from reaching into that modules folder and importing "internal" files. I.e. I want to limit other modules to only importing what is exported by the root index.js.
To illustrate:
/src/framework/core
./index.js
./someInternalFile.js
/src/framework/components/dataGrid
I don't want the dataGrid module above to be able to access the internal file. Only what is exported in index.js
One approach would be to have sepearate webpack configs to build the core module into npm modules and use file: references in package.json. However this adds a build step and would mean that if developers change core they need to re-build core and re-run npm install and then restart the webpack-dev-server.
This is severely limiting as it becomes a very slow developer experience. Ideally I would like to acheive this logical separation of modules but maintain the webpack/filewatcher/hot/redeploy experience we currently enjoy.
Is there another way I can acheive this?
A way to address this issue is to break your application into multiple npm packages. To reduce the overhead of doing this you may want to consider a "mono repo" (AKA "multi-package repo".) This essentially allows you to package modules in your application into separate npm packages but keep the module hot loading and other things you want through the magic of symbolic links. Essentially you make a symbolic link in your node_modules folder to the other modules inside your repo.
I have found a number of tools that do this:
https://github.com/clux/symlink
https://github.com/lerna/lerna
https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/
https://github.com/boltpkg/bolt

NPM: should I use one of my dependencies' dependencies, or should I explicitly install it into the project at the root level?

TL;DR Summary
(I'm using Lodash as an example here, but it could be any other package)
In addition to using Lodash for its own purposes, my application also needs to import JavaScript from an NPM package that I created. The JavaScript in this package relies on Lodash as well. It's possible that each codebase may have installed a different version of Lodash. If JavaScript in my application and JavaScript in the installed package both import the same Lodash functions, then I want to avoid having to bundle two different versions of the same function. I understand that NPM is able to resolve the dependencies and that nothing will break, but the size of my application's JavaScript bundle will continue to grow as each codebase uses functions from different versions of the same libraries. It sounds like the only way to keep the versions in sync is to continuously monitor them and upgrade manually when appropriate, or to use the version provided by the installed package directly, without ever installing it into my application's own package.json. Is doing the latter a bad idea and is there no better way?
Original Question
At my company, we've created a Git repository that houses most of our UI component code. This repository also contains a static site generator, which transforms our UI component code into a "living style guide" website. The purpose of this website is to document and showcase our UI components on the web (similar to how PatternLab works).
We also distribute this code via NPM, so that it can be shared across multiple projects. Each project installs the NPM module as a dependency, then imports the SASS and JavaScript files contained within. The JavaScript has been written in ES6 and has not been bundled or transpiled. We've intentionally chosen not to distribute browser-ready code. Instead, each project is responsible for compiling its own SASS and bundling/transpiling its own JavaScript.
Most of our UI component JavaScript is simple and does not depend on any third-party libraries, so it's easy to import into our projects. However, some of our newer, more complex components rely on NPM packages such as Lodash, which presents a problem.
Obviously, we need to install Lodash in order for the static site generator to showcase our Lodash-reliant components inside of a web browser. Similarly, projects that consume the NPM package will also need to install Lodash, in order to create instances of these same components. This forces us to install Lodash twice: once in the UI component project, then again in the project that consumes the NPM package. This is problematic because the two projects could potentially install different versions of Lodash, which could lead to compatibility issues and/or increase the size of our JavaScript bundle.
One solution that I've discovered is to include Lodash under dependencies instead of devDependencies, in the UI component project. This way, when external projects install the UI component NPM module, Lodash will be installed along with it. This gives the project "free" access to Lodash without needing to explicitly install it itself. This is possible because NPM installs packages in a single, flat directory hierarchy, so it doesn't seem to matter if your project installs a package directly or if one of its dependencies exposes it as a dependency in it's own package.json. This eliminates version conflicts, since you don't have to install the package twice.
My question is, does this violate NPM best practices or is this how NPM is intended to work? After reading the NPM documentation and Googling for answers, it doesn't seem like this should be a problem. However, if what I'm suggesting is a bad idea, how else can I accomplish what I'm trying to do?
Here's a quick visual aid:
main.js
node_modules/
lodash/
foo/
bar.js
node_modules/
lodash/
main.js imports and uses Lodash. It also imports foo/bar.js, which uses Lodash too, but a potentially different version. Both files are ES6. main.js gets bundled and transpiled before being sent to the browser.
if is something you are directly using you should specify it in your package.json. it will be installed anyways but this way it will ensure that if your dependency removes that package as a dependency your project won't break

Angular 2 Bundling and Minification

I watch a lot of tutorials of angular 2, and I couldn't some questions:
1- Should I use webpack for minification and bundleling?
2- Should I minify and bundle the js of the components itselfs.
3- Should I minify and bundle the js services that the components expose e.g.
personService.js is used in person.ts?
4- What happens with the path
of the service I provide inside the component, now it will be in one
file located in another place? Should I change the path of the
service called in the component depending on if I'm in development o
production?
How are you currently handling module loading for your applications? I'm not as familiar with webpack, but SystemJS offers a builder/bundler that will do all of this for you then all you need to include in your html is the script for your bundled/built file.
I haven't used Webpack but SystemJS worked well for me. Gulp can be used to build, minify, and bundle all your code using a system.config.js to worry about the file locations of your source and dependencies.
Here is an example of Tour of Heroes where all the Typescript source is bundled into one JS file.
Angular CLI now makes all of this really easy, supporting bundling and minification (using WebPack underneath, but without any need to set it up), and Ahead-of-Time template compilation, which massively reduced the bundle size.
See: Angular 2: Reduce app size (in addition to bundling/minification)
It also sets up development and production environments, which you can import into components if you have different settings in dev vs. prod, and you can make your own custom environments and use those too.

Import class dynamically with browserify on client side

I'm using browserify to create a bundle file of my app.
This app get from some rest a list of js file links, each link is a bundle of tool that my app should import and init the imported tool class.
My problem is that browserify doesn't support dynamically import/require like require('www.example.com/myTool.js'). It only knows to require modules from his bundle which I created on the build process.
Do you have any idea how I can keep using browserify and still require files on the fly? I try to import requirejs and systemjs but I had some problems to create a bundle with browserify.
I can force the tool's developers to support any kind of require mechanism, even something I can make. so fill free to write any kind of solution you think.
Thanks

Categories

Resources