Submodules in custom React component library - javascript

I've created a React component library which is getting quite big now, so I want to split it into submodules but am unable to do so.
The current setup is like this:
src/index.ts
export * from "./components";
export * from "./utils";
src/components/index.ts
export { default as CustomComponentOne } from "./CustomComponentOne";
export { default as CustomComponentTwo } from "./CustomComponentTwo";
src/utils/index.ts
export { default as utilOne } from "./utilOne";
export { default as utilTwo } from "./utilTwo";
package.json
{
...
"main": "dist/index.js",
"module": "dist/index.modern.js",
"source": "src/index.ts",
"scripts": {
"build": "microbundle-crl --no-compress --no-sourcemap --format modern,cjs",
...
},
...
}
My goal is to enable imports like:
import { CustomComponentOne } from "my-library/components"
import { utilOne } from "my-library/utils"
while preserving imports like
import { CustomComponentOne, utilOne } from "my-library"
The last import example is how everything is now imported, but I want to add imports like the two above. I was able to do this with compiling the project with tsc instead of microbundle-crl because this generated a .js file for each .ts file, but microbundle-crl creates 1 .js file as output. But SCSS files etc were not compiled with tsc (obviously).
Does anybody know how to go about this?

Related

How to share Vite config in monorepo?

I am trying to make monorepo using Turborepo. I have a lot of Vue projects there and I need to share Vite config across all applications. Here's how I'm trying to achieve this.
I have package named #monorepo/configs:
packages/
configs/
package.json
index.ts
vite.config.base.ts
package.json:
{
"name": "#monorepo/configs",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "index.ts",
"types": "index.ts",
"files": [
"./src/tsconfig.base.json",
"./src/vite.config.base.js"
]
}
vite.config.base.ts:
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
// regular config
export const ViteConfigBase = defineConfig({
resolve: {
alias: {
// some aliases
}
}
})
index.ts:
export { ViteConfigBase } from './vite.config.base'
And in the other application's vite.config.ts:
import { fileURLToPath, URL } from 'node:url'
import { ViteConfigBase } from '#monorepo/configs/src/vite.config.base' // notice import from 'src'
import { defineConfig, mergeConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
export default defineConfig(mergeConfig(
ViteConfigBase,
{
plugins: [vue()],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url))
}
}
}
))
Here I import ViteConfigBase as a file from 'src' folder and this is the error that I get after npm run dev:
> #monorepo/sandbox#0.0.0 dev
> vite
failed to load config from C:\Users\user\Desktop\Code\Personal\monorepo\apps\Sandbox\vite.config.ts
error when starting dev server:
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\user\Desktop\Code\Personal\monorepo\packages\Config\src\vite.config.base.js from C:\Users\user\Desktop\Code\Personal\monorepo\apps\Sandbox\vite.config.ts not supported.
Instead change the require of vite.config.base.js in C:\Users\user\Desktop\Code\Personal\monorepo\apps\Sandbox\vite.config.ts to a dynamic import() which is available in all CommonJS modules.
If I change import from 'src' folder to import from index, like this:
import { fileURLToPath, URL } from 'node:url'
import { ViteConfigBase } from '#monorepo/configs' // <-- here
import { defineConfig, mergeConfig } from 'vite'
// other config...
Then the error will be this:
> #monorepo/sandbox#0.0.0 dev
> vite
failed to load config from C:\Users\user\Desktop\Code\Personal\monorepo\apps\Sandbox\vite.config.ts
error when starting dev server:
C:\Users\user\Desktop\Code\Personal\monorepo\packages\Config\index.ts:1
export { ViteConfigBase } from './src/vite.config.base'
^^^^^^
SyntaxError: Unexpected token 'export'
OOokkay, I've seen it before. Let's try "type": "module" in package.json. Now that's the error:
> #monorepo/sandbox#0.0.0 dev
> vite
failed to load config from C:\Users\user\Desktop\Code\Personal\monorepo\apps\Sandbox\vite.config.ts
error when starting dev server:
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for C:\Users\user\Desktop\Code\Personal\monorepo\packages\Config\index.ts
And this is where I'm stuck. I need those files to be .ts for sure (and I'm not sure if they would work if I change extention to .js).
I could also easily fix this by just adding the build step, but I don't think it is that necessary and there should be the way around. The build step will add a lot of overhead to development process and the code itself. I've tried it and the dist folder was around ~4Mb for no reason. Also, I won't be able to use "Go to definition" feature in this case, and last but not least, it has to be rebuilt after every change, so I really wish to avoud this step and just use raw config files everywhere.
If you using Turborepo, how about this way?
/
├── apps
| ├── app1
| | ├── src
| | ├── package.json
| | └── vite.config.ts
| └── app2
| ├── src
| ├── package.json
| └── vite.config.ts
├── packages
| └── viconfig
| ├── index.js
| └── package.json
// apps/app1/package.json
{
"name": "app1",
"devDependencies": {
"viconfig": "workspace:*",
"vite": "4.0.0"
}
}
// apps/app1/vite.config.ts
import { defineConfig } from "vite";
import customConfig from "viconfig";
export default defineConfig(() => {
return {
...customConfig,
};
});
// packages/viconfig/index.js
import path from "node:path";
export default {
resolve: {
alias: {
"#": path.resolve(process.cwd(), "src"),
},
},
};
// packages/viconfig/package.json
{
"name": "viconfig",
"main": "index.js",
"type": "module",
"types": "index.js"
}

TypeScript and Rollup: "Cannot read properties of undefined (reading 'v4')" when using the uuid package

I am trying to use the uuid package in my TypeScript project, but I am encountering an error when I try to use the v4 method. The error message is: "Cannot read properties of undefined (reading 'v4')".
I have also included the #rollup/plugin-node-resolve, #rollup/plugin-commonjs, and #rollup/plugin-replace plugins in my rollup.config.js file in order to handle the uuid package, which is a Node.js-style package.
Here is my rollup.config.js file:
import typescript from "rollup-plugin-typescript2";
import { terser } from "rollup-plugin-terser";
import postcss from "rollup-plugin-postcss";
import image from "#rollup/plugin-image";
import json from "#rollup/plugin-json";
import commonjs from "#rollup/plugin-commonjs";
import nodeResolve from "#rollup/plugin-node-resolve";
import builtins from "rollup-plugin-node-builtins";
import replace from "#rollup/plugin-replace";
export default [
{
input: "src/index.ts",
output: {
file: "dist/bundle.js",
format: "cjs",
},
external: ["uuid"],
plugins: [
image(),
terser(),
postcss(),
nodeResolve(),
commonjs(),
replace({
require: "function(){}",
preventAssignment: true,
}),
builtins(),
typescript({
tsconfig: "tsconfig.json",
}),
json(),
],
},
];
In this project, I am using web components for my application. I am using the uuid package to generate unique IDs for these components, but I am encountering an error when I try to use the v4 method.
In one of my web component class, an example usage is like this:
import {v4 as uuidv4} from "uuid"
export class ExampleWebComponent extends HTMLElement{
...
private setInitialAttributes() {
this.setAttribute("customer-id", uuidv4());
}
...
connectedCallback() {
if (this.shadowRoot) {
this.setInitialAttributes();
}
}
}
And then I import this web component at App.ts file:
import { ExampleWebComponent } from "./web-components/ExampleWebComponent";
And define it to window.customElements:
function defineWebComponents() {
window.customElements.define("example-web-component", ExampleWebComponent);
}
export default defineWebComponents;
and I finally call the defineWebComponents function in index.ts file:
import defineWebComponents from "./App";
defineWebComponents();
const newComponent = document.createElement("example-web-component");
console.log(newComponent.getAttribute("customer-id");
I was expecting the v4 method to generate a new UUID. I was also expecting the #rollup/plugin-node-resolve, #rollup/plugin-commonjs, and #rollup/plugin-replace plugins to correctly handle the uuid package and allow me to use it in my TypeScript code.

Rollup full file path for node_modules or bundle each external module in separate dir

I'm try to work with this test js-file, I want to compile test ES module for browsers via Rollup.
import { v4 as uuidv4 } from 'uuid';
export default function () {
console.log(uuidv4());
}
I made npm i for this package.json
{
"dependencies": {
"uuid": "^8.3.2"
},
"devDependencies": {
"#rollup/plugin-node-resolve": "^13.0.4"
}
}
rollup.config.js
// rollup.config.js
import nodeResolve from '#rollup/plugin-node-resolve';
export default {
input: ['src/main.js'],
output: {
name: 'bundle',
dir: 'dst',
format: 'es'
},
external: ['uuid'],
plugins: [ nodeResolve({ browser: true }) ]
};
After rollup work I get:
import { v4 } from 'uuid';
function main () {
console.log(v4());
}
export { main as default };
#1
Can I get full path to node_modules js-file with my prefix?
For example for lib uuid (node_modules/uuid/dist/esm-browser/index.js) I want:
// for prefix '/assets/js/lib/'
import { v4 } from '/assets/js/lib/uuid/dist/esm-browser/index.js';
or may be just node_modules lib-file path:
import { v4 } from 'node_modules/uuid/dist/esm-browser/index.js';
#2
Can I make es-bundle in separate dirs for each external module (from package json) that was imported by my js-code?
Remove modules from external section.
Use preserveModules: true - docs.

Unable to use a component as a plugin when it has its own vuex store setup

I have a component thats more like an app with its own vuex store. I need to wrap this up as a plugin and then use inside another app where there will be a main store. I tried doing it but no success. Below are the things I did...
To wrap it, I defined a file called bundle.js wherein I have set the following code. I will be using this file as a target for building.
import Scheduler from './App.vue';
import store from './storeBuild';
export default {
install(Vue, options) {
if (!options || !options.store) {
throw new Error('Please initialise plugin with a Vuex store.')
}
options.store.registerModule('schedulerLib', store)
Vue.component('scheduler', Scheduler)
}
}
Here is the package.json where I have the build script
{
"name": "scheduler",
"version": "0.1.0",
"private": true,
"main": "dist/scheduler.common.js",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build-bundle": "vue-cli-service build --target lib --inline-vue --name scheduler ./src/bundle.js" // The script to build the bundle
},
"dependencies": {
..........
}
}
and my store file will directly export the object instead of creating a store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default {
namespace: true,
state: {
layout: 'main-layout',
nestedObject: {},
},
mutations: {
// Has more than 20 handlers
},
actions: {
},
modules: {
}
}
After running the build-bundle I had the code along with my dist folder push into the git.
Then I add it as a package in my other app using the gitlab link
(ie) yarn add git+https://abc:sdbfkn45234ADFGDF#gitlab.com/abc/task-scheduler.git#master // here task-scheduler is the repo name
I was able to solve the early stage barrier and now Iam able to see the store setup of the library but still I am not able to see the UI of the libary inside my layout.
Note that the layout that I have inside the plugin itself is dependent on one the state variables so the plugins store is not integrated properly then layout wont show up.
Below is the App.vue file of the plugin
<template>
<div id="scheduler">
<component v-bind:is="layout"></component>
</div>
</template>
<script>
import { mapState } from "vuex";
import MainnLayout from "./components/layouts/MainnLayout";
import WbsLayout from "./components/layouts/WbsLayout";
import "#/components/global";
export default {
name: "scheduler",
computed: {
...mapState(["scheduleLayout"]),
layout() {
return this.scheduleLayout;
},
},
components: {
"mainn-layout": MainnLayout,
"wbs-layout": WbsLayout,
},
};
</script>
<style lang="scss">
#scheduler {
font-family: Lato, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-width: 940px;
}
</style>
I have added the screenshots below for reference
As suggested by #Dan,I updated the change in the plugin component and was able to bring up the module in the parent app
and my vuex in the parent app now shows the module but still I have errors on my console

Babel + nodejs TypeError: Cannot read property 'default' of undefined

I'm trying to export/import a bunch of files in nodejs using babel.
I never has a problem doing so in react projects or typescript libraries, but there's something wrong here obviously related to babel.
I have a folder exporting some files in its index.js like so :
export { default as Foo } from './Foo'
export { default as Bar } from './Bar'
...
There's an export default in each one, of course.
When I try to import some or all of them in another file like so :
import { Foo } from '../foobar'
// or
import * as foobar from '../foobar'
Here's what I got :
/build/dist/foobar/index.js:9
return _Foo.default;
^
TypeError: Cannot read property 'default' of undefined
My babel config is :
{
"presets": [
["#babel/env", { "targets": { "node": "current" } }]
],
"plugins": [
["babel-plugin-root-import", {
"rootPathSuffix": "src"
}],
"#babel/plugin-proposal-class-properties"
]
}
A few days back tried to achieve the same. Here is the way it worked for me
The correct way to export is in index.js:
import {Foo} from './Foo/';
import {Bar} from './Bar/';
export { Foo };
export { Bar };
In Main.js
import {Foo} from './path-to-index.js'

Categories