Questions about serving a Vue Component Library as an NPM package - vue.js

Gist for my vite and tsconfigs is here.
Disclaimer: Very new to how packages and modules work. I'm a yung'un who never had to think beyond import/export. So I may have used the term "tree-shaking" too many times below.
I'm looking to move some re-used Vue components from old projects into a shared private package that I can consume through npm. I do not intend to consume it via CDN, only Vite projects. Here is the directory structure of the "package" I've come up with:
my_components
| package.json
│ vite.config.ts
│ tsconfig.json
| tsconfig.vite.json
│
└───src
│ │ index.ts
│ │
│ └───components
│ | index.ts
│ | MyButton.vue
│ | MyDropdown.vue
| | ...
| |
| └───assets
| |
| └───sass
| |
| | style.scss
| | ...
│
└───dist
│ my-lib.es.js
│ style.css
└───types
| index.d.ts
| src/MyButton.vue.d.ts
| src/MyDropdown.vue.d.ts
I am using Vite in library mode and generating es module + bundled.
The resulting build is around 1MB of CSS and 300kb of JavaScript (before gzip). The reason for this is that there a lot of one-off components that may or may not be used in the consuming project but still bring in their own unique dependencies (fullcalendar, prismjs, tiny mce, etc.). The ideal scenario is that my shared package can have a tonne of dependencies while my consuming project still only includes what it uses in its own build.
I have a few questions and doubts and gaps in knowledge about the whole process:
A. How do I make the sass variables be able to be overridden?
This is an important requirement since styling the components uniquely per project would be impossible otherwise (?).
It seems the only way to do this would be to add src/assets/sass/style.scss as an export in my package.json file. The consumer of this package would then include this file instead of the bundled/minified dist/style.css and build it themselves. This is how Bootstrap's npm package does it.
B. How do dependencies and tree-shaking work for libraries distributed like this? How is the build process changing my existing code?
B.1) I only used import/export throughout my code. Is the resulting bundled file dist/my-lib.es.js one huge module, or does it somehow manage to preserve multiple module definitions inside a single file?
This project depends on bootstrap, prismjs, quill, fullcalendar, etc. The list goes on. All of these are in my devDependencies.
B.2) Can I expect the full source of these dependencies to have been included in my bundle, or are these "tree-shaken" by Vite when building my package dist?
B.3) When I import this bundled JS inside my consuming project, is it "tree-shakeable"? If not, how do I make it so? I want to minimize what is built in the final project app to only what is used from my shared package.
C. Is there a way to distribute without building anything at all?
Since this package is only meant to be consumed by other (Vite) projects, is there a way to package everything without building a dist folder at all? In this scenario, I would publish my src folder only and the consuming project would be expected to include/import/build what they require. This should definitely minimize what goes into the final project build, right!?
C.1) If this is possible (and I haven't found any online sources about this), how would I set-up Typescript, ESLint and Vite in the consuming project to properly process the raw code?
P.S. I want it setup as a package instead of a git repository because I might delegate the shared package development to someone else later on, and an npm package is a simpler thing to consume than a git sub-repository IMO. Feel free to point out why I may be wrong in this, but please do not do so as the main solution in your answer.
D. Analyzing everything!
I imagine I would have a better grasp of the above concepts if I could analyze what is being included in builds on both levels (shared package build, and consuming project's application build). However, I currently know of no ways or tools or workflows to analyze such things (owing to my inexperience). Recommendations?

Related

Replicating libman unpkg with a local filesystem

I noticed I can use libman to download many libraries into my Asp.Net Core app in a nice way. E.g. I can easily get the latest #microsoft signalr:
However, in my application I can't rely on external package sources and would like to store the packages I need within my network.
I noticed that libman supports "filesystem" mode, so I copied all the files downloaded from unpkg onto my local network drive, let's call it "L:"
/ L:
| local_unpkg
| #microsoft
| signalr
| 5.0.2
| package.json
| README.md
| src
| ... // a lot of files
| dist
| browser
| cjs
| esm
| ... // other subfolders
When I try using "filesystem" provider, I get only the files in directly in the folder I specify, without nested folders:
Is there a way to import entire packages that way, without manually specifying all the subfolders in the libman.json file?
If not, what's the recommended approach for using the tool in an environment, when I don't want to rely on external package sources?
The filesystem provider specifically does not support recursive directory contents. With the other providers, the contents of the package are available all at once via the catalog metadata. But with file paths, and especially network file paths, iterating the file system can lead to extremely poor performance in large (or deep) directory structures. In many cases, you'd be typing out the path and the wizard would try to evaluate the contents as you type (e.g. once you typed L:\ it would recognize that directory and enumerate all its contents recursively, over the network).

Use vue-cli-service to build a library, how to transpile?

I'm trying to build a library (mostly some .vue components) to reuse in different projects (no public npm) with vue-cli-service. Apparently everything its already setup, and I can confirm that the build is fine (js, and css). However, I'm unable to use it in a separate project as an external module because it uses the spread operator (and probably more ES20XX features no yet parsed).
Module parse failed: Unexpected token (2683:8)
You may need an appropriate loader to handle this file type.
| params() {
| const queryParams = {
| ...this.filters,
| ...this.sorting,
| ...this.config.params,
This is the standard command I'm using to build the library
vue-cli-service build --target lib --name [mylibname] ./src/components/index.js
By default the bundle should be already polyfilled but it seems to me that it's not the case.
I've read that I might change the webpack configuration on the project I'm using into, but I'm against parsing the whole node_module folder and also I would love to just have the simplest workflow possible (like import a module and its css).
So my question is, how to polyfill my bundle to be perfectly usable in no matter what Vue project without any hassle ?
Ok, it seems that reinitializing the project with vue-cli without typescript and with separated configuration files instead of into package.json was a good idea, as now is transpiled as needed.
var queryParams = _objectSpread({}, this.filters, {}, this.sorting, {}, this.config.params);
Unfortunately the hidden configuration of vue-cli webpack can't help to see what has changed.

Is there a way to copy an existing library but being able to modify the new one?

I need to be able to create a new library from an existing one. For example, I would like to be able to copy Qt5::Widgets and create a library with an other name, but with every setting staying the same. Later, I would change some locations on the newly made library without changing the original library.
An example can help to understad:
I have Qt5::Widgets and would like to make an exact copy of said library and call it ModifiedQt5Widgets. I want every property to be the same. Then, I would modify some properties such as IMPORTED_LOCATION_DEBUG on this new library. I also want this new library to behave the same as Qt5::Widgets when I link it. This seems to be difficult since this is an imported library. Is there a function or a way to just do like copy_existing_library(ModifiedQt5Widgets Qt5::Widgets)?
Basically, I want to make an alias library, but I want to be able to edit this new library.
Edit
My use case is that I have 4 possible configurations: Debug, MinSizeRel, RelWithDebInfo, Release. This is the tree that I will have in my build folder:
├── bin
| ├── Debug
| ├── RelWithDebInfo
| ├── MinSizeRel
| └── Release
I have a bunch of external libraries that I link to. I need to be able to link to these libraries, and then copy all these shared libraries in the appropriate bin/[CONFIGURATION] folder. Once that it compiled, I need my generated project in each folder to have all external dependencies to be in the same folder and be independent of the environment.
Also, this needs to work on Mac, Windows, and Linux. It seems that Windows may have issues with a solution based on using RPATH. I also need a way to find the dlls that match the libs that I link with.

Why I have too many packages inside my node_modules?

I am new, and when i first created my app based on the documentation using npm create-react-app i found it there were a lot of package included inside folder node_module when i code and i only use react and react DOM and etc from the basic.
node_modules
acorn
timer
ansi
and many more
I wonder if anyone can help my how to understand each use inside the node_module or where can i find the documentation for each use?
or how can i just reduce to what i want to use only to decrease the app size?
The answers are 2:
because you're using an automated scaffolding tool, which essentially does everything for you, and, you have just to code, it is supposed to locally deploy all the packages it needs to work (for example webpack is needed to bundle your code, babel to transpile it, ...
under node_modules you will find all the packages of the whole app. That's means you will find both your dependencies and the dependencies of your dependencies (this rule has some exceptions and you can find them in the npm documentation.
example:
// your code depends on A
var dependency = require('A');
// but then, inside your A dependency you can also find something similar to:
var b = require('B');
how can i just reduce to what i want to use only to decrease the app size?
You basically can't do it. They are all needed.
Most of the libraries that we pull from npm have dependencies. You may use only react and react-dom but there are react-scripts that require lots of stuff. I don't think that you have to worry about the size of the node_modules. That's not what you are suppose to ship in production.
If you want to see what are these all modules about you may open their folder and fine README.md file.

Manage assets in Laravel 5

Could someone explain the right approach in managing assets in Laravel 5?
For example, let's imagine I want to install some plugins using bower. The recommended way, as I got it, to keep all files into /vendor/bower_components. So I got some css, some images, fonts and javascript files withing the plugins.
Also I have a "app.less", where I import everything I need, like #import ('../../../vendor/bower_components/someplugin/somestyle.css'). The problem though that I don't have images/js/fonts in my public directory. Okay, I saw that you can use gulp copy function. However, when the number of plugins is getting higher, how I am supposed to manage where each plugin keeps its pictures or other files?
Actually I wanted to try semantic ui. I've downloaded it with bower. I know nothing about semantic ui, but there is a dist folder with semantic-ui.css. Also there are some fonts files withing themes/basic/assets/fonts. If I just copy it to public, it'll be public/themes/basic/assets/fonts. Then I import semantic-ui.css into my app.les and it'll find necessary fonts. What if I have some other plugins, it'll become unbearable to manage it all.
What is the typical workflow for this problem? The most simple way is just something like put everything into public and include it manually using <link> and <script> tags, but it'll require a lot of queries.
And why it's bad to keep all bower_components inside public? On the analogy of composer, we don't have autoloader for bower, so there is a mess of assets.
You are correct in the recommended place to put bower_components. It's not recommended to put bower_components in the public directory because it contains ALL the files in that specific package, not just the file you need to include in your HTML.
Since your talking about Laravel5, it is recommended to utilize laravel-elixir to manage assets. http://laravel.com/docs/5.0/elixir which utilizes gulp and can compile less, sass or various other files. I don't have any experience with semantic ui, but it looks to be similar to bootstrap. Without a SaaS or Less version available on npmjs.org you would need to copy the necessary files to your public directory. Elixir provides a simple way to copy files or whole directories from bower_components to your public directory.
The easiest way to include all the files needed without a ton of or is to use saas or less.
Personally what I do is this using node
var elixir = require('laravel-elixir');
var nodeDir = './node_modules/'; //This is the node directory(base directory) where all vendor files are downloaded in your case might be different
/*
|--------------------------------------------------------------------------
| Elixir Asset Management
|--------------------------------------------------------------------------
|
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
| for your Laravel application. By default, we are compiling the Sass
| file for our application, as well as publishing vendor resources.
|
*/
elixir(function(mix) {
mix the styles and copy fonts to my public/css folder
mix.styles([
'bootstrap/dist/css/bootstrap.css',
'font-awesome/css/font-awesome.css'
], './public/css/app.css', nodeDir)
.copy(nodeDir + 'font-awesome/fonts', 'public/fonts')
.copy(nodeDir + 'bootstrap/fonts', 'public/fonts');
//mix javascript from node directory and output to public/js/ folder
mix.scripts([
'jquery/dist/jquery.js',
'bootstrap/dist/js/bootstrap.js'
], './public/js/app.js', nodeDir);
});