Npm link not linking because of vite - javascript

I'm trying to link two applications together. I have two projects. Both projects using Vue(2). One being the main project and the other a componet lib. I succesfully linked the two projects together with npm link. However my main project is giving an error.
ERROR Failed to resolve entry for package "#hitfoyb/my-component-library". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "#hitfoyb/my-component-library". The package may have incorrect main/module/exports specified in its package.json.
My main application is using vite and the component application is using webpack.
in my main.js I'm importing it like any other lib
import thqComponentLibrary from "#hitfoyb/my-component-library/dist/MycomponentLibrary.umd";
import "#hitfoyb/my-component-library/dist/MycomponentLibrary.css";
Vue.use(MycomponentLibrary);
my main application vite.config.js
optimizeDeps: {
include: ['#hitfoyb/my-component-library']
},
Any help on why the application is giving the error and how do I resolve it?

Related

How to do module resolution when an npm package contains multiple namespaces/submodules

A project I am working with is using this package: https://www.npmjs.com/package/#ethersproject/abstract-provider
within an SDK we are building..
After installation, the SDK node_modules folder contains the #ethersproject directory which contains an abstract-provider directory as well as multiple other directories, each their own namespace with separate package.json files.
We use the code in the sdk as follows:
import { Provider } from '#ethersproject/abstract-provider';
and this works fine for webpack based projects which import our SDK (such as a React app using create-react-app).
When I want to use our SDK in a project which DOESN'T use a bundler such as webpack (such as a very simple frontend pulling in our sdk with importmap as here: https://github.com/unegma/rainprotocol__verify-gating), we are getting an error:
Failed to resolve module specifier "#ethersproject/abstract-provider". Relative references must start with either "/", "./", or "../".
I'm assuming this is because our SDK doesn't know how to resolve #ethersproject/abstract-provider because abstract-provider is a submodule of #ethersproject (which isn't even a module itself).
What is the way to solve this issue? Do we need to create a decs.d.ts file in our SDK root which contains something like: declare module "#ethersproject/abstract-provider; or is there a different way to do this?

cannot use import statement outside a module on built exe with electron-forge

I am creating an app with Electron and Vue (using js not ts).
When I run the app using npm run electron:serve the app runs fine.
I now want to build a Windows exe so I can distribute my app. I have tried using electron-builder, electron-packager and electron-forge. Whenever I can get the build to finish, running the exe throws the cannot use import statement outside a module error (referring to the first import statement it finds, i.e. import { app, protocol, BrowserWindow } from 'electron').
I've tried adding "type":"module" to my package.json but (due a bug in Vue, according to this question), that throws Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]
I've also tried changing all my import statements to require but this doesn't work because some of the node modules I'm using use import and the error just throws for those instead.
I'm tearing my hair out over this. Where do I go from here?
UPDATE:
I have found a workaround for the Vue bug and posted my findings on the linked question. I can now add "type":"module" to my package.json.
However, I now get an error thrown when I run npm run electron:serve and from my built exe:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: <my_project_root>\dist_electron\index.js
require() of ES modules is not supported.
require() of <my_project_root>\dist_electron\index.js from <my_project_root>\node_modules\electron\dist\resources\default_app.asar\main.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
To be clear, I'm not using require in any of my source code, but the compiled(?) version does?
What's going on here?
UPDATE 2:
As requested, here is a minimal reproducible example that maintains original folder structure, configs and package.json

Is there a way to integrate stencil components into frameworks locally without publishing to NPM?

I am currently testing stencil js. For now I want to write stencil components and include them within a VUE/React project. The official website of stencil already shows how to integrate them within a framework (https://stenciljs.com/docs/overview). But they assume that your own stencil component library has already been published to npm.
Is there a way to integrate stencil components locally into a framework to test them without publishing them first?
Yes, you can use npm-link for that.
cd my-component-lib
npm link
cd ../my-app
npm link my-component-lib # or whatever you have named the project in package.json
If you have any problems with that (e. g. with paths not resolving properly), you can also try to pack your package and install the packed version instead, using npm-pack:
cd my-component-lib
npm pack
cd ../my-app
npm install ../my-component-lib/my-component-lib-1.0.0.tgz
Linking is preferable though because changes to your component library will be reflected immediately (after a rebuild), whereas with packing you'd have to re-pack and re-install it after every change to your lib.
Instead of publishing or packing your packages, you could utilize TypeScript's path mapping feature.
This allows you to write your import statements just as you would with a published package, but behind the scenes TypeScript maps the imports to their given source code location.
Here's an example of a tsconfig.json with path mapping added to the compiler options:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"ui-components": ["libs/ui-components"],
"ui-components/loader": ["libs/ui-components/dist/loader/index.cjs.js"],
"ui-components-react": ["generated/ui-components-react/src/components.ts"]
},
...
As you can see, it has 3 mappings: the path to the core Stencil components ui-components, the path to the generated React components which are exposed as ui-components-react, as well as the generated loader ui-components/loader which provides the bridge between the Custom elements and the React wrappers.
I created a full working example for Stencil Web Components with generated bindings and wrappers for React that comes without the need of publishing any package: Nx Stencil React.
Please note that this answer is based on #stencil/core 1.14.0 or below. Future versions may have a different approach on generating the framework integrations.
I've had quite a bit of trouble with this myself so will provide an answer specifically for Vue 3 as Stencil's Framework Integrations guide seems to refer only to Vue 2.
Starting Projects
Stencil Component
Following the Getting Started guide run npm init stencil. Choose the component option.
There was a bug in v2.7.0 so I update to v2.8.0 with npm i #stencil/core#latest --save-exact
Build the project with npm run build
Optional
By default, the stencil project configures multiple build targets, to make it easier to see what build files are being used you can edit the stencil config to only include the custom elements bundle:
\\ stencil.config.ts
outputTargets: [
{
type: 'dist-custom-elements-bundle',
},
{
type: 'dist',
esmLoaderPath: '../loader',
},
],
You also need the 'dist' type for the .d.ts typings file to be generated with your custom-elements (not sure why).
Vue 3 App
Using a globally installed Vue CLI #vue/cli#4.5.13 create a new Vue 3 default project.
Using Stencil in Vue 3
Install your stencil component project
npm install --save ../<path>/stencil-component as a dependency of your vue app.
Fixing NPM Module Resolution
Following the Vue CLI - Troubleshooting guide add a vue.config.js file to the root of your Vue 3 project with the line config.resolve.symlinks(false),
Skipping Component Resolution
In the same file we need to configure Using Custom Elements in View
\\ vue.config.js
module.exports = {
chainWebpack: (config) => {
config.resolve.symlinks(false),
config.module
.rule("vue")
.use("vue-loader")
.tap((options) => ({
...options,
compilerOptions: {
isCustomElement: (tag) => tag.includes("my-"),
},
}));
},
};
Framework Integration
Now we can declare the custom elements, but in the Vue 3 way
\\ main.js
import { createApp } from 'vue'
import App from './App.vue'
import { defineCustomElements } from "stencil-component";
defineCustomElements();
createApp(App).mount('#app');
You can now use your custom component as normal. Here's what my App.vue file looked like after hacking the example starter code:
<template>
<my-component first="Andy" middle="2K" last="11"></my-component>
</template>
<script>
import { MyComponent } from "stencil-component";
export default {
name: 'App',
components: {
MyComponent
}
}
</script>
Errors
No ESLint Config
No ESLint configuration found in /<path>/stencil-component/dist/custom-elements.
Fixed by telling webpack not to resolve symlinks in vue.config.js
Uncaught TypeError: class constructors must be invoked with 'new'
This error occurs in the browser after a successful compilation.
Resolved by telling webpack / vue not to resolve your custom components
Custom Component Not Visible
There are no errors and your component is showing in the DOM inspector but not appearing on the page.
You need to defineCustomElements() in main.js.
Component not found
I've had some variation of this error when trying to import and use my component but haven't been able to reproduce it just now. Doing all of the above and restarting the dev server works fine for me.
For local integration, you can reference the esm.js file inside www/build folder which can be used in the head tag of the Vue/React project.
For eg if you have the below 2 apps
stencil-components - stencil components
stencil-react - sample react app which will consume the components.
Once you run stencil-components by npm run start it will be hosted at 3333 (by default).
Including below line in head ofindex.html of stencil-react will integrate components with live reloading on change.
<script type="module" src="http://localhost:3333/build/stencil-components.esm.js"></script>

NodeJS require/import module from higher level directory

I am using node v9.2.0. Want to load module located in higher level directory.
Here is minimal example: https://github.com/skkap/es6importtest
Suppose I have following dir structure:
/common/
index.mjs
/app/
app.mjs
/node_modules/
package.json
index.mjs contains some logic and also imports some npm module, like graphql.
import graphql from 'graphql'
...
export default graphql
I want to import common/index.mjs module from app.js.
import common from '../common/'
And get the following error:
Error: Cannot find module graphql
Any ideas where the problem is?
I checked, it also works the same wat with require(): https://github.com/skkap/es6importtest/tree/master/requireTest
P.S. Please do not recommend using npm packages or webpack for that, this question is about the particular problem described above.

Webpack / NPM: Use build version of installed module instead of re-building from source

I would like to use the dat.GUI library for a project that's build with Webpack 2. If I install the module via npm -install --save-dev dat.gui and then try to import it using import * as DAT from 'dat.gui'; I get the following error when Webpack is trying to compile my project:
ERROR in ./~/dat.gui/src/dat/controllers/NumberControllerSlider.js
Module not found: Error: Can't resolve 'style' in
'/home/me/myProject/node_modules/dat.gui/src/dat/controllers'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix
when using loaders.
I know this error occurs when using Webpack 2 to build Webpack 1 based projects. But why is Webpack even trying to build the module if there already is a build version inside node_modules/dat.gui/build';? Is there a way to tell Webpack or NPM to use the existing build version without trying to re-build it?
When importing a node module, webpack looks into its package.json and uses the main field as entry of the module, similar to what Node.js does (webpack looks for more fields by default, see resolve.mainFields).
Since for dat.gui the main field does not point to the built version but to the source, which actually inlines loaders as seen in dat.gui#0.6.1 - NumberControllerSlider.js for the styleSheet import, and that is not a good idea in general and certainly not to publish.
But you can import the built version by specifying the corresponding path. So your import would be:
import * as DAT from 'dat.gui/build/dat.gui.js';
If you'd like to still import just dat.gui you can configure resolve.alias to point to the built version as follows:
resolve: {
alias: {
'dat.gui': 'dat.gui/build/dat.gui.js'
}
}
With that you can use your original import statement:
import * as DAT from 'dat.gui';

Categories