I'm using Jhipster 4 with Angular 2 and need to use a 3rd party lib in my project, however the library is no on npm and doesn't have an .d.ts file. I need to include directly the js.
Import inside vendor.ts works for libraries installed via npm but won't work with my js, how can I use this file in my project?
I am also trying to figure this out right now.. I actually couldn't get libraries installed via yarn to work by importing them in the vendor.ts file either though..
My current workaround (...until I can figure out the correct way to do this) was to copy the .js files I needed into src/main/webapp/content/js/ and reference it from webpack.common.js in the CopyWebpackPlugin plugin:
Under plugins in webpack.common.js, I added an entry to CopyWebpackPlugin:
new CopyWebpackPlugin([
{ from: './node_modules/core-js/client/shim.min.js', to: 'core-js-shim.min.js' },
{ from: './node_modules/swagger-ui/dist', to: 'swagger-ui/dist' },
{ from: './src/main/webapp/swagger-ui/', to: 'swagger-ui' },
{ from: './src/main/webapp/favicon.ico', to: 'favicon.ico' },
{ from: './src/main/webapp/robots.txt', to: 'robots.txt' },
{ from: './src/main/webapp/i18n', to: 'i18n' },
{ from: './src/main/webapp/content/js/FooLib.js', to: 'FooLib.js'}
]),
And then added an import to the webapp/index.html
<script src='FooLib.js'></script>
And then declared it in the component that I was using it with:
declare var Foo: any;
While it's less than ideal, you can just use the plain-old-js. Link it as you would normally in the index.html, and then in any TypeScript code that you need to use it put a declare of the library at the top of the file. So, for example:
import { Component } from '#angular/core';
declare myAwesomeJsLibrary: any;
#Component(/* brevity*/)
export class AppComponent {
constructor() {
myAwesomeJsLibrary.doSomethingAwesome();
}
}
It doesn't give you any kind of autocompletion, of course, but you can always create your own interfaces and d.ts files for it if you really want. This way you can at least get it working.
Related
I am transitioning a Vue 3 website from Javascript to TypeScript. Mathjax is loaded from a CDN, and this field from a custom component which worked previously:
watch: {
note_content: function () {
this.$nextTick(MathJax.typesetPromise);
}
}
now generates a static error which should translate as:
Can not find name 'MathJax'.ts(2304)
How can I solve this ?
You'll need to install #types/mathjax
I want to migrate my Vue 2 project from webpack to Vite.
And have to use 3rd party web components that built with lit-element.
Those components throws errors during the runtime (by vue):
Unknown custom element: < foo-component > - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
And also (by lit-element)
Failed to set the 'adoptedStyleSheets' property on 'ShadowRoot':
Failed to convert value to 'CSSStyleSheet'.
As far as I can see those 3rd party web components do only this in theirs index files (inside node_modules):
import FooComponent from './FooComponent';
customElements.define('foo-component', FooComponent);
So before (with webpack setup) I just imported them and everything used to work. Well, actually for webpack lit-scss-loader was used also for those components.
I assume that Vite perhaps needs some additional configuration, or maybe something similar to "webpack" loader is needed here, but not sure what direction I have to move.
What I'm doing wrong?
Configure #vite/plugin-vue to ignore Lit elements, e.g., elements starting with my-lit in their registered name:
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// treat all components starting with `my-lit` as custom elements
isCustomElement: tag => tag.startsWith('my-lit'),
},
},
}),
],
})
demo
A couple of steps needed.
Imagine I have 3rd party webcomponents named "foo". So all of them are in node_modules/#foo.
I need to do these steps:
Tell Vite that all components starting with "foo-" are webcomponents.
isCustomElement: (tag) => tag.startsWith('foo-')
Add "postcssLit" plugin to help vite to prepare css for the webcomponents.
Tell to Vite how to threat css paths for webcomponents.
'~#foo': fileURLToPath(new URL('./node_modules/#foo', import.meta.url))
Here is the full config:
//vite.config.ts
import postcssLit from 'rollup-plugin-postcss-lit';
export default defineConfig({
plugins: [
vue(
{
template: {
compilerOptions: {
// 1. Tell Vite that all components starting with "foo-" are webcomponents
isCustomElement: (tag) => tag.startsWith('foo-')
}
}
}
),
vueJsx(),
// 2. This "postcssLit" plugin helps to make css for the webcomponents
postcssLit()
],
resolve: {
alias: {
// 3. Tell to Vite how to threat css paths for webcomponents
'~#foo': fileURLToPath(new URL('./node_modules/#foo', import.meta.url))
}
}
});
I currently have a large private NPM library which is being consumed by several other teams' apps across the business. At the moment the library is being published as one large single file (like the main lodash file) but this is causing application bundle size to be bloated as some of the applications don't need a large chunk of what is in the library.
So at the moment the apps are importing something like this
import { SomeReactComponent, someHelperFunction } from 'my-private-library';
What I want to achieve is the library published with individual modules similar to how Lodash, so the above would become:
import SomeReactComponent from 'my-private-library/lib/SomeReactComponent';
import someHelperFunction from 'my-private-library/lib/someHelperFunction';
I can get Webpack to output output the library in this format using multiple entry points, but what I can't get to work is getting Webpack to split out shared dependencies of each of those modules. So say the files look something like this:
src/SomeReactComponent.jsx
import React from 'react'
import SOME_CONST_STRING from '../constants';
const SomeReactComponent = () => {
return (
<div>You are using {SOME_CONST_STRING}</div>
);
}
export default SomeReactComponent;
src/someHelperFunction
import SOME_CONST_STRING from '../constants';
export default function someHelperFunction() {
return `This is just an example of ${SOME_CONST_STRING}`;
}
My Webpack is outputting the individual files, but it's not splitting out common code in a way that an app can consume the library. So notice above the SOME_CONST_STRING which is imported in each of the modules, Webpack is putting this code in both of the exported files.
My Webpack config looks a bit like this (removed other setting for brevity)
module.exports = {
entry: {
SomeReactComponent: './src/SomeReactComponent',
someHelperFunction: './src/someHelperFunction',
},
output: {
path: './lib',
library: 'MyPrivateLibrary'
libraryTarget: 'umd',
filename: '[name].js'
}
// removed other setting for brevity
}
I have tried using the splitChunks optimization setting like this
module.exports = {
entry: {
SomeReactComponent: './src/SomeReactComponent',
someHelperFunction: './src/someHelperFunction',
},
output: {
path: './lib',
library: 'MyPrivateLibrary'
libraryTarget: 'umd',
filename: '[name].js'
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
// removed other setting for brevity
}
which does chunk the code, but when I try to use the library in an app after doing this I get errors along the lines of (ERROR in TypeError: __webpack_require__(...) is not a function).
My question is can anyone see what I'm doing wrong? Is what I'm trying to achieve even possible with Webpack? Are there any example out there (as I can't find any) on how to do this?
Apologies for the example code, as my library is private I'm not able to use real-code examples.
Did you get success to achieve what you were trying to achieve in above scenario. I am working on the same use case and was facing similiar issue. After diagnosing it i found it that when we define library then in parsed module webpack add this in this object as window.myWebpackJsonpMyPrivateLibrary in minified main chunk which is undefined. if you remove the library and libraryTarget from webpack then you will not face this issue.
In my case i faced another issue that required chunk(s) are not being loaded when this is used as install dependency in another project.
I'm trying to load a JavaScript file into my angular component. I have loaded the full minified version from here: https://github.com/blueimp/JavaScript-Load-Image/blob/master/js/load-image.all.min.js and also put any related scripts in my scripts folder.
When the code runs and reaches 'loadImage', the console fires an error:
ERROR ReferenceError: loadImage is not defined
What's the best way to resolve this?
Component
import '../../../assets/scripts/load-image.all.min.js';
declare var loadImage: any;
...
dropChangeHandler(e) {
e.preventDefault()
e = e.originalEvent
var target = e.dataTransfer || e.target
var file = target && target.files && target.files[0]
var options = {
maxWidth: 1000,
maxHeight: 1000,
canvas: true,
pixelRatio: window.devicePixelRatio,
// downsamplingRatio: 0.5,
orientation: true
}
if (!file) {
return
} else {
this.currentFile = file;
if (!loadImage(file, this.updateResults, options)) {
}
}
}
I think this question is slightly different to the other 'import JS files into angular' because I have a feeling it might be to do with the library I'm trying to import. However, I'm unsure and seeking advice on this one.
The library you are trying to import doesn't support es6 modules. Because of no exports in the library, it doesn't add any variables to your scope after import.
In your particular case easiest is to add the script to index.html:
<script src="assets/scripts/load-image.all.min.js"></script>
and call a method in the component with
window.loadImage(file, this.updateResult, options)
I use window because library directly binds itself to window.object
More details
To use javascript modules with typescript add allowJs: true to tsconfig.js file.
import './file is known as an import for side-effects only and don't change the scope of the module, but can access to global app scope. It can help you in case you want to extend already imported module.
You could import js module different ways:
For CommonJs modules it's possible to use import * as ModuleName from './modulePath.js'; in your component.ts file and call as ModuleName.exportedMethod().
to the Angular pipeline to be sure it is loaded with the module which
imports it. If you are using angular cli, simply include it to you
angular-cli.json in the section apps/scripts:
{
"apps":
...
"scripts": [
"assets/scripts/load-image.all.min.js"
]
}
If you don't use angular-cli, you can include to your index.html:
<script src="assets/scripts/load-image.all.min.js"></script>
I think you need to export the wanted function in your imported file.
you must unsusure that the library is will be compiled
Add the script in angular-cli.json
"scripts": [
....
'<path to file>/assets/scripts/load-image.all.min.js'
....
]
then
declare var loadImage: any;
I tried to use gulp, browserify, watchify, and babelify to compile a standalone js module.
The options is like this:
const browserifyOpts = {
debug: true,
entries: path.join('src', 'index.js'),
standalone: 'Goo',
transform: [
'babelify',
],
};
My JS module is as follows:
export default class Goo {
constructor() {
this.a = 'hello';
}
}
It compiles fine. But when I include it in a script tag in a html file, the Goo module is wrapped inside window.Goo.default, that is, I cannot directly use:
new Goo();
but have to use:
new Goo.default();
Any idea where went wrong?
Thanks!
The easiest option would be to wrap this yourself by having your index.js file contain something like
module.exports = require('./main').default;
and move your current index.js to main.js. Then you'll be set.
As the other answer says, you can potentially use babel-plugin-add-module-exports, but that is not something I'd generally recommend because while it fixes this problem, it also introduces the possibility that you could accidentally write import/export pairs that work but are not spec-compliant.
By default, Babel 6 handles default module exports differently. If you want to use the legacy version, you can use the add-module-exports plugin.
Either add that into your .babelrc, or add it as an option in Babelify.
More information from this Github Issue:
has to do with the new way Babel handles default exports. if you dont
want to have to reference the default key, you need to use this
plugin: https://github.com/59naga/babel-plugin-add-module-exports