I am having trouble getting Intellisense to work completely with ES6 imports.
Doing the following from /index.js gets Intellisense to work correctly:
However, doing the following from /index.js breaks Intellisense:
The directory structure is:
| modules
|-- cars.js
|-- index.js
| index.js
| jsconfig.json
The contents of each file are:
modules/cars.js
export default {
audi: 'R8',
dodge: 'Durango',
};
modules/index.js
import cars from './cars';
export default {
cars,
};
jsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "commonjs"
},
"exclude": [
"node_modules"
]
}
Cars isn't a named export of modules/index.js. The default export of modules/index.js is an object, which then contains cars. To get what you want, make the contents of modules/index.js this:
export { default as cars } from './cars';
Related
I am making esm modules from rollup with following configuration:
...,
output: [
{
dir: "./build",
format: "esm",
sourcemap: true,
preserveModules: true,
preserveModulesRoot: "src",
},
],
The generated output creates each file according to the content, but I have divided each module into subfolders and in this example, the folder Components have a file that includes and exports each sub-component
components.ts looks like this:
export { default as BNButton } from "./BNButton/BNButton";
export { default as BNCard } from "./BNCard/BNCard";
export { default as BNDonutChart } from "./BNDonutChart/BNDonutChart";
export { default as BNFooter } from "./BNFooter/BNFooter";
export { default as BNHeader } from "./BNHeader/BNHeader";
export { default as BNInlineSvgIcon } from "./BNInlineSvgIcon/BNInlineSvgIcon";
export { default as BNJumpToNavigation } from "./BNJumpToNavigation/BNJumpToNavigation";
export { default as BNSideNavigation } from "./BNSideNavigation/BNSideNavigation";
export { default as BNTopMobileNavigation } from "./BNTopMobileNavigation/BNTopMobileNavigation";
export { default as BNTopNavigation } from "./BNTopNavigation/BNTopNavigation";
index.ts on root /src includes Components/components.ts
When rollup runs and generate the files, compoents.ts is just ignored and not generated. Rollup jumps over this file and imports the files directly into index.js without the components.js.
That is bad because I would like to use components.js and import the modules also from this file. Does anyone know why rollup is doing this, and is there a way to make rollup not do this but rather generate a components.js which exports the imported modules?
I'm working on project that uses Typescript and webpack. I have to import json files, and I have to do it in two ways:
I have to import project's package.json as a module. This has already been implemented previously.
Have to import some json schemas as resources loadable by url. This is what I'm working on right now.
Using package.json (already implemented)
To import package.json, the tsconfig.json contains:
{
"compilerOptions": {
"resolveJsonModule": true,
"paths": {
"package.json": ["./package.json"]
}
},
}
And webpack config has:
/**
* Determine the array of extensions that should be used to resolve modules.
*/
resolve: {
extensions: [".js", ".ts", ".tsx", ".json"],
plugins: [
new TSConfigPathsPlugin({
configFile: path.join(__dirname, "../../tsconfig.json"),
logLevel: "info",
extensions: [".js", ".jsx", ".ts", ".tsx"],
mainFields: ["browser", "main"],
baseUrl: tsConfig.baseUrl,
}),
],
},
And this is how package.json is used:
import packageJson from "package.json";
//...
const release = `${packageJson.version}-${process.platform}`;
This is completely type-safe: ts checks that my package.json has version field. This is working as intended and I don't want to break it.
Using schema json files (what I'm implementing)
To add support for json schemas, I've added them with filenames matching .schema.json$ and have added this to webpack config:
module: {
rules: [
{
test: /\.schema.json$/,
type: "asset/resource",
},
],
},
And this to a global type declaration file:
declare module "*.schema.json" {
declare const uri: string;
export default uri;
}
I thought that by doing that, Typescript would interpret import such a file as a simple string. I've been following this example.
However, when I import the schema file in my project:
import someSchemaUri from "./schemas/some-name.schema.json";
// ...
uri = someSchemaUri;
I still get type error:
Type '{ ... }' is not assignable to type 'string'.
Changing resolveJsonModule
If I set resolveJsonModule option to false, this problem goes away, but importing package.json from the previous section starts giving an error:
Module 'package.json' was resolved to 'secret/path/package.json', but '--resolveJsonModule' is not used.
How do I configure my project so that Typescript would interpret these files as a string, but at the some don't lose type safety when I import package.json from the previous section?
As I know, there's no way to override json types once --resolveJsonModule was set.
May you consider to disable that flag and write types for package.json manually? It's not time-consuming since you use only one package.json field.
declare module '*.schema.json' {
const uri: string;
export default uri;
}
declare module '*package.json' {
const content: {
version: string;
};
export default content;
}
I am using both vue single-file components and separating of markup and logic to .pug and .ts files respectively. If you interesting why I don't unify is please see the comments section.
Problem
import template from "#UI_Framework/Components/Controls/InputFields/InputField.vue.pug";
import { Component, Vue } from "vue-property-decorator";
console.log(template);
#Component({
template,
components: {
CompoundControlBase
}
})
export default class InputField extends Vue {
// ...
}
In development building mode exported template is correct (I beautified it for readability):
<CompoundControlBase
:required="required"
:displayInputIsRequiredBadge="displayInputIsRequiredBadge"
<TextareaAutosize
v-if="multiline"
:value="value"
/><TextareaAutosize>
</CompoundControlBase>
In production mode, my markup has been lowercased. So, the console.log(template) outputs:
<compoundcontrolbase
:required=required
:displayinputisrequiredbadge=displayInputIsRequiredBadge
<textareaautosize
v-if=multiline
:value=value
></textareaautosize>
</compoundcontrolbase>
Off course, I got broken view.
Webpack config
const WebpackConfig = {
// ...
optimization: {
noEmitOnErrors: !isDevelopmentBuildingMode,
minimize: !isDevelopmentBuildingMode
},
module: {
rules: [
{
test: /\.vue$/u,
loader: "vue-loader"
},
{
test: /\.pug$/u,
oneOf: [
// for ".vue" files
{
resourceQuery: /^\?vue/u,
use: [ "pug-plain-loader" ]
},
// for ".pug" files
{
use: [ "html-loader", "pug-html-loader" ]
}
]
},
// ...
]
}
}
Comments
To be honest, I don't know why we need ? in resourceQuery: /^\?vue/u, (explanations are welcome).
However, in development building mode above config works property for both xxxx.vue and xxxx.vue.pug files.
I am using below files naming convention:
xxx.pug: pug file which will not be used as vue component template.
xxx.vue.pug: pug file which will be used as vue component template.
xxx.vue: single-file vue component.
xxx.vue.ts: the logic of vue component. Required exported template from xxx.vue.pug as in InputField case.
Why I need xxx.vue.ts? Because of this:
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
Neither public methods/fields nor non-default methods are visible for TypeScrpt xxx.vue files. For the common (non-applied) components, I can't accept it.
Repro
🌎 GitHub
Step 1: Install dependencies
npm i
Step 2: Let's check the development building first
npm run DevelopmentBuild
In line 156 of DevelopmentBuild\EntryPoint.js, you can check that below pug template:
Alpha
Bravo OK
has been compiled properly:
Step 3: Problem on production build
npm run ProuductionBuild
You can find the lowercased tags in the column 13:
You can also open index.html in your browser and check the console.log() output with compiled TestComponent.
The problem is the "html-loader". It has the option minimize set to true in production mode (html-loader/#minimize).
I had a similar problem in angular and had to unset some options like (see for reference html-minifier-terser#options-quick-reference).
// webpack.config.js
{
test: /\.pug$/u,
oneOf: [
// for ".vue" files
{
resourceQuery: /^\?vue/u,
use: [ "pug-plain-loader" ]
},
// for ".pug" files
{
use: [ "html-loader", "pug-html-loader" ]
}
],
options: {
minimize: { // <----
caseSensitive: false // <----
} // <----
}
},
I have a simple .json file outside of my project. Like this :
| common
| configuration.json
| angular-app
| src
| app
| my-component
| my-component.component.ts
| angular.json
In my-component.component.ts, i want to import configuration.json. I tried import configuration from '../../../../common.configuration.json' but Angular just keep throwing this error :
ERROR in src/app/record/record.component.ts(4,23): error TS2732: Cannot find module '../../../../common/configuration.json'. Consider using '--resolveJsonModule' to import module with '.json' extension
And when i try ng serve --resolveJsonModule, i got this error : Unknown option: '--resolveJsonModule'
I can't move configuration.json. The common directory is shared with other projects.
How do you import a local json file in an Angular project ?
If you're using typescript 2.9+ (Angular 6.1+), you can import JSON modules so it will get compiled into the application. Older version don't support this so that may be your issue.
All you need to do is make sure the following three compiler options are enabled in your tsconfig.json:
{
...
"compilerOptions": {
"resolveJsonModule": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
...
}
}
Then you can import JSON modules in any TS file:
import jsonContents from '../../contents.json';
I'm not exactly sure what you mean but I guess you want to use the config values in your component, right?
According to this tutorial this can be fixed by creating a type definition file json-typings.d.ts in your app root folder with the following contents:
declare module "*.json" {
const value: any;
export default value;
}
Try by using http call:
this.http.get(`yourpath/..../common/configuration.json`).subscribe((resp: any) => {
console.log(resp)
});
I have a JSON file that looks like following:
{
"primaryBright": "#2DC6FB",
"primaryMain": "#05B4F0",
"primaryDarker": "#04A1D7",
"primaryDarkest": "#048FBE",
"secondaryBright": "#4CD2C0",
"secondaryMain": "#00BFA5",
"secondaryDarker": "#009884",
"secondaryDarkest": "#007F6E",
"tertiaryMain": "#FA555A",
"tertiaryDarker": "#F93C42",
"tertiaryDarkest": "#F9232A",
"darkGrey": "#333333",
"lightGrey": "#777777"
}
I'm trying to import it into a .tsx file. For this I added this to the type definition:
declare module "*.json" {
const value: any;
export default value;
}
And I'm importing it like this.
import colors = require('../colors.json')
And in the file, I use the color primaryMain as colors.primaryMain. However I get an error:
Property 'primaryMain' does not exist on type 'typeof "*.json"
With TypeScript 2.9.+ you can simply import JSON files with benefits like typesafety and intellisense by doing this:
import colorsJson from '../colors.json'; // This import style requires "esModuleInterop", see "side notes"
console.log(colorsJson.primaryBright);
Make sure to add these settings in the compilerOptions section of your tsconfig.json (documentation):
"resolveJsonModule": true,
"esModuleInterop": true,
Side notes:
Typescript 2.9.0 has a bug with this JSON feature, it was fixed with 2.9.2
The esModuleInterop is only necessary for the default import of the colorsJson. If you leave it set to false then you have to import it with import * as colorsJson from '../colors.json'
The import form and the module declaration need to agree about the shape of the module, about what it exports.
When you write (a suboptimal practice for importing JSON since TypeScript 2.9 when targeting compatible module formatssee note)
declare module "*.json" {
const value: any;
export default value;
}
You are stating that all modules that have a specifier ending in .json have a single export named default.
There are several ways you can correctly consume such a module including
import a from "a.json";
a.primaryMain
and
import * as a from "a.json";
a.default.primaryMain
and
import {default as a} from "a.json";
a.primaryMain
and
import a = require("a.json");
a.default.primaryMain
The first form is the best and the syntactic sugar it leverages is the very reason JavaScript has default exports.
However I mentioned the other forms to give you a hint about what's going wrong. Pay special attention to the last one. require gives you an object representing the module itself and not its exported bindings.
So why the error? Because you wrote
import a = require("a.json");
a.primaryMain
And yet there is no export named primaryMain declared by your "*.json".
All of this assumes that your module loader is providing the JSON as the default export as suggested by your original declaration.
Note: Since TypeScript 2.9, you can use the --resolveJsonModule compiler flag to have TypeScript analyze imported .json files and provide correct information regarding their shape obviating the need for a wildcard module declaration and validating the presence of the file. This is not supported for certain target module formats.
Here's how to import a json file at runtime
import fs from 'fs'
var dataArray = JSON.parse(fs.readFileSync('data.json', 'utf-8'))
This way you avoid issues with tsc slowing down or running out of memory when importing large files, which can happen when using resolveJsonModule.
It's easy to use typescript version 2.9+. So you can easily import JSON files as #kentor decribed.
But if you need to use older versions:
You can access JSON files in more TypeScript way. First, make sure your new typings.d.ts location is the same as with the include property in your tsconfig.json file.
If you don't have an include property in your tsconfig.json file. Then your folder structure should be like that:
- app.ts
+ node_modules/
- package.json
- tsconfig.json
- typings.d.ts
But if you have an include property in your tsconfig.json:
{
"compilerOptions": {
},
"exclude" : [
"node_modules",
"**/*spec.ts"
], "include" : [
"src/**/*"
]
}
Then your typings.d.ts should be in the src directory as described in include property
+ node_modules/
- package.json
- tsconfig.json
- src/
- app.ts
- typings.d.ts
As In many of the response, You can define a global declaration for all your JSON files.
declare module '*.json' {
const value: any;
export default value;
}
but I prefer a more typed version of this. For instance, let's say you have configuration file config.json like that:
{
"address": "127.0.0.1",
"port" : 8080
}
Then we can declare a specific type for it:
declare module 'config.json' {
export const address: string;
export const port: number;
}
It's easy to import in your typescript files:
import * as Config from 'config.json';
export class SomeClass {
public someMethod: void {
console.log(Config.address);
console.log(Config.port);
}
}
But in compilation phase, you should copy JSON files to your dist folder manually. I just add a script property to my package.json configuration:
{
"name" : "some project",
"scripts": {
"build": "rm -rf dist && tsc && cp src/config.json dist/"
}
}
In my case I needed to change tsconfig.node.json:
{
"compilerOptions": {
...
"resolveJsonModule": true
},
"include": [..., "colors.json"]
}
And to import like that:
import * as colors from './colors.json'
Or like that:
import colors from './colors.json'
with "esModuleInterop": true
You should add
"resolveJsonModule": true
as part of compilerOptions to tsconfig.json.
Often in Node.js applications a .json is needed. With TypeScript 2.9, --resolveJsonModule allows for importing, extracting types from and generating .json files.
Example #
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"resolveJsonModule": true,
"esModuleInterop": true
}
}
// .ts
import settings from "./settings.json";
settings.debug === true; // OK
settings.dry === 2; // Error: Operator '===' cannot be applied boolean and number
// settings.json
{
"repo": "TypeScript",
"dry": false,
"debug": false
}
by: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html
Another way to go
const data: {[key: string]: any} = require('./data.json');
This was you still can define json type is you want and don't have to use wildcard.
For example, custom type json.
interface User {
firstName: string;
lastName: string;
birthday: Date;
}
const user: User = require('./user.json');
In an Angular (typescript) app, I needed to include a .json file in my environment.ts. To do so, I had to set two options in tsconfig:
{
"compilerOptions": {
"moduleResolution": "node",
"resolveJsonModule": true
}
}
Then, I could import my json file into the environment.ts:
import { default as someObjectName } from "../some-json-file.json";
You can import a JSON file without modifying tsconfig you tell explicitly that you are importing JSON
import mydata from './mydataonfile.json' assert { type: "json" };
I know this does not fully answer the question but many people come here to know how to load JSON directly from a file.
Enable "resolveJsonModule": true in tsconfig.json file and implement as below code, it's work for me:
const config = require('./config.json');
Note that if you using #kentor ways
Make sure to add these settings in the compilerOptions section of your tsconfig.json (documentation):
You need to add --resolveJsonModule and--esModuleInterop behind tsc command to compile your TypeScript file.
Example:
tsc --resolveJsonModule --esModuleInterop main.ts
require is a common way to load a JSON file in Node.js
in my case I had to change: "include": ["src"] to "include": ["."] in addition to "resolveJsonModule":true because I tried to import manifest.json from the root of the project and not from ./src