Import npm module as source code - javascript

I want to import the source code for vue-form-generator to make some changes to the source code. Being new to Node and Javascript, I really have no idea what I'm doing. Can someone please guide me through the steps?
Since my Vue project is in Typescript, previously when I was using npm install vue-form-generator I'd created vfg.d.ts
declare module "vue-form-generator" {
const VueFormGenerator: any;
export default VueFormGenerator;
}
and my main.ts was
import VueFormGenerator from 'vue-form-generator';
Vue.component('VueFormGenerator', VueFormGenerator);
Now I have copied everything from their /src to my /src/component/form-generator but have no idea how to make it so I can use as previously.

If you are creating your own fork of vue-form-generator, you may add type declarations right there as well.
create file index.d.ts in your copy of src/component/form-generator:
const VueFormGenerator: any;
export default VueFormGenerator;
There is no need to have declare module ... in there because this index.d.ts is right next to index.js, so TypeScript compiler should find it when you import it as
import VueFormGenerator from './relative-path-to/form-generator/index';
and generated javascript code will find it as index.js there. Note that the import path must be relative because otherwise, without any path mapping, it will look for the module in node_modules, not in your sources.
You also have to remove all references to the previous type declaration file, vfg.d.ts, in your project.

Related

How to include a global file type declaration in a TypeScript (Node.js) package

I'm working on a package that I am planning to publish publicly on npmjs. Let's call it the "text package".
I would like that by default when installing that package, you can import .txt files directly and get the correct type (out of the box), like this:
import text from './file.txt'
The text variable would be of type string because the package would have defined its type, using something like this (in a global.d.ts):
declare module '*.txt' {
export const text: string;
export default text;
}
If I include that global.d.ts in my package, and that I import something from this package, then I will automatically get the correct type when importing a .txt file.
But the problem is sometimes I would just need to import a .txt file without importing anything from the "text package", which is why I was wondering if there is some sort of way, as you install a package to install a global type that does not require to import anything else for the type to apply.
In other words, as soon as you install my "txt package" the declare module '*.txt' would apply to my entire project out of the box.
Is there even a way to do this, or whoever installs my package would have to declare their own global type (e.g., declarations.d.ts) to be able to import .txt files globally?
I know that even if the import type works, it will still require Webpack or another bundler to really work but this question is just about the type.
The short answer is:
TypeScript does not support Global types without importing the file referring to the type.
More details:
One example that I found doing this was Next.js - when creating a TypeScript app using npx create-next-app#latest --typescript you can start importing *.css files (for example) and get the correct type.
Where I got confused is that I originally thought that the type was coming from the next-env.d.ts but even when I deleted the file, *.css import was still working in Visual Studio code. But the reason it was, is because a file in the pages directory were importing Next.js' index.d.ts file.
Basically, in Visual Studio Code, as soon as your import a type somewhere in your project, if it's global, it will be accessible everywhere.
Workaround
So what can be done with the current TypeScript capabilities? To support new file types, you will need a file loader such as Webpack. The logical thing to do would be to add a reference to the file type declaration in the file loader itself. This way, as soon as you configure your file loader to be able to import the file, you will inherit the type:
create a txt.d.ts in our package's source directory (e.g. src) - you can use any name for the file, it's not important
if you are using eslint, add an entry to ignore the type file (e.g. 'src/*.d.ts' in your ignorePatterns option
Since you are adding a d.ts file in your source that is not managed by tsc, you need to add a script that will perform the following actions:
Copy txt.d.ts in the target directory of the compiled files for your package
Add this line at the top of your package's file loader (e.g. loader/index.d.ts: /// <reference types="../txt" />\r\n - this will link the declaration file back into your package. Note that you can add this reference to any file of your package.
This workaround will only work once you import the file referencing back to the declaration - this is the only way TypeScript can be made aware that this type exists (see https://github.com/microsoft/TypeScript/issues/49124).
Another alternative could also be to add manual steps (in a readme file) to add a global type declaration file.
to bundle global types, do the following. form typescript
specify default typings directory at typeRoots. .e.g "typeRoots": ["./src/types"].
create a file /src/types/global.d.ts in the specified directory
declare your types in the file inside declare global {} and make sure to have export {} if you don't already export anything.

Node package.json Export VS Imports fields

So after a bit of digging around the diferences from Export and Imports declared from the package.json file I was wondering what is the best use case for both?
For example the following fields:
"name": "node-api",
"exports": {
".": "./application.js",
"./config/*": "./config/*.js",
"./controllers": "./controllers/index.js",
"./helpers/*": "./helpers/*.js",
"./models": "./models/index.js",
"./routes": "./routes/index.js"
},
"imports": {
"#config/*": "./config/*.js",
"#controllers": "./controllers/index.js",
"#helpers/*": "./helpers/*.js",
"#models": "./models/index.js",
"#routes": "./routes/index.js"
}
And then each of the following with their output in the main JS file:
import routes from './routes/index.js'; // works
import routes from './routes'; // error - ERR_UNSUPPORTED_DIR_IMPORT
import routes from 'node-api/routes'; // works (with the package name)
import routes from '#routes'; // works (without the package name but need the #)
So why not just use the imports field?
In my opinion seems friendlier than to type your package name every time you want to import your own file.
Based on the NODE JS official docs (https://nodejs.org/api/packages.html) it says the following: "The "exports" field allows defining the entry points of a package when imported by name loaded either via a node_modules lookup or a self-reference to its own name.".
Then for the imports field says the following: "it is possible to define internal package import maps that only apply to import specifiers from within the package itself."
From my testing to reference my relative (my own created) files I just use the imports field so that I don't need to type in the package for every import that I want.
So long story short, when is it best to use exports and imports field and in my case does it make sense to use only imports?
exports is for consumers, while imports is for the internal usage (it even uses the same prefix as private class fields). If you aren't publishing a package, then you don't need to care about exports. Its main usecase is to organize the API surface of the module without spilling all its implementation guts on the consumer.

Angular import external javascript file, getting no exported member and compile errors

I am writing an angular component and got a open source module working with npm install. Now I made some some changes and want to import the javascript file like so
import { ModuleName } from './../../ModuleFolder/ModuleName';
When I place the cursor above the ModuleName inside the bracket, I see the highlighted red error saying Module has not export member 'ModuleName';
In my ts code, I have referenced the Module like so
object: ModuleName; which is also complaining.
I google and the post says using npm install but I don't want to add this module to my node_module list. I am moving the folder out to make my customization.
I also tried the following but it is not working
import './../../ModuleName.bundle.min.js';
I am wondering does the name of the Module needs to be registered somewhere to be able to reference it in my component?
Thanks for any help.
Use 'declare' after the import statements
declare const _moduleName;
For example:
I am using Swiper.js library using cdn. In my angular component, I refer it using a declare keyword.
declare const Swiper;
var mySwiper = new Swiper('.swiper-container', { /* ... */ });
I got external libraries working in Angular by following the following links
https://hackernoon.com/how-to-use-javascript-libraries-in-angular-2-apps-ff274ba601af

TypeScript import class from another project / module?

I am trying to alter the following build task written in Typescript in the following project:
https://github.com/Microsoft/app-store-vsts-extension/blob/master/Tasks/app-store-promote/app-store-promote.ts
I need an import like the one shown below (or something else that lets me uses the methods in the ios-signing-common module):
import sign = require('ios-signing-common/ios-signing-common');
That import is used in another file in another project:
https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/XamariniOS/xamarinios.ts, however that project is also the same as the ios-signing-common exists in.
https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/Common/ios-signing-common/ios-signing-common.ts
So is it possible to import the ios-signing-common module into the app-store-promote file?
I have tried adding the github path "Microsoft/vsts-tasks" as dependency in package.json, and it downloads it to node_modules, but I still can't resolve the ios-signing-common module.
I hope that any of you can lead me to a solution. :)
I guess I just needed to read up on how module resolving works.
I solved it by adding vsts-tasks as dependency in package.json:
"dependencies": {
"vsts-task-lib": "^0.9.7",
"vsts-tasks": "Microsoft/vsts-tasks"
},
Then I changed the require path to the following:
import sign = require('Agent.Tasks/Tasks/Common/ios-signing-common/ios-signing-common');
And it works!
EDIT - It could compile, but doesn't seem to work when I run it. It fails in the script because it can't find Agent.Tasks/Tasks/Common/ios-signing-common/ios-signing-common.

Why can't I import sprintf-js in TypeScript

I have a TypeScript file into which I'm importing third-party libraries.
import * as _ from 'lodash'; // Works great!
import * as moment from 'moment'; // Works great!
import {vsprintf} from 'sprintf-js'; // Compiler error
As my comments explain, the first two imports work great, but the sprintf-js import does not. I get the following compiler error:
Error TS2307: Cannot find module 'sprintf-js'.
Without a doubt, I have sprintf-js inside of my node_modules folder. I'm not very knowledgeable about node modules. I'm guessing that the sprintf-js libarary does something different than lodash or moment and that TypeScript doesn't like it. How can I make this work?
You will need to add a typing definition for sprintf-js. Depending on your setup - if you have TSD installed and setup with your project, it would be a case of running:
tsd query sprintf-js --action save
otherwise, you can have a read here:
http://definitelytyped.org/
or simply download the typing definition and include it in the project root folder:
https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/sprintf-js/sprintf-js.d.ts

Categories

Resources