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
I use fountainJS Angular2 generator with Typescript and Systems.js
for scaffolding the project.
https://github.com/FountainJS/generator-fountain-angular2
But I got the issue, I can't add the component to the project.
When I put import {GOOGLE_MAPS_DIRECTIVES}
I get this error
system.src.js:1057 GET http://localhost:3000/node_modules/angular2-google-maps/core/index.js 404 (Not Found)
I went through that
https://angular-maps.com/docs/getting-started.html
'getting started' section and added some code to jspm.config.js file but I don't have angular-cli-build.js file inside my project.
My jspm.config.js
SystemJS.config({
packageConfigPaths: [
'npm:#*/*.json',
'npm:*.json',
'github:*/*.json'
],
map: {
'angular2-google-maps': 'node_modules/angular2-google-maps',
'#angular/common': 'npm:#angular/common#2.0.0-rc.4',
'#angular/compiler': 'npm:#angular/compiler#2.0.0-rc.4',
'#angular/core': 'npm:#angular/core#2.0.0-rc.4',
'#angular/http': 'npm:#angular/http#2.0.0-rc.4',
'#angular/platform-browser': 'npm:#angular/platform-browser#2.0.0-rc.4',
'#angular/platform-browser-dynamic': 'npm:#angular/platform-browser-dynamic#2.0.0-rc.4',
'#angular/router': 'npm:#angular/router#3.0.0-beta.2',
'es6-shim': 'npm:es6-shim#0.35.1',
'os': 'github:jspm/nodelibs-os#0.2.0-alpha',
'process': 'github:jspm/nodelibs-process#0.2.0-alpha',
'reflect-metadata': 'npm:reflect-metadata#0.1.3',
'rxjs': 'npm:rxjs#5.0.0-beta.6',
'ts': 'github:frankwallis/plugin-typescript#4.0.16',
'zone.js': 'npm:zone.js#0.6.17'
},
packages: {
'angular2-google-maps/core': {
defaultExtension: 'js',
main: 'index.js' // you can also use core.umd.js here, if you want faster loads
},
'github:frankwallis/plugin-typescript#4.0.16': {
'map': {
'typescript': 'npm:typescript#1.8.10'
}
},
'github:jspm/nodelibs-os#0.2.0-alpha': {
'map': {
'os-browserify': 'npm:os-browserify#0.2.1'
}
}
}
});
You are getting node_modules/angular2-google-maps/core/index.js 404 (Not Found) because node_modules is not made available by web server used by npm run serve.
If you need node_modules to be accessible by client code, you have to add route for it in conf/browsersync.conf.js:
routes: {
'/node_modules': 'node_modules',
Alternatively, you could use jspm instead of npm to install angular2-google-maps:
jspm install angular2-google-maps
and jspm would modify jspm.config.js to add correct mapping for angular2-google-maps.
BUT, after 404 error is fixed, I'm getting now
system.src.js:123 Uncaught (in promise) Error: (SystemJS) core_1.NgModule is not a function
TypeError: core_1.NgModule is not a function
which probably means that the latest angular2-google-maps is incompatible with angular2-rc4 installed by generator-fountain-angular2.
In Webpack 2.0 (#2.1.0-beta6), if I go to import a file that points to a file that doesn't exist, I get a build time error.
//x.js
import { foo } from './y'
//y.js
export function foo () { return 5 }
If I go to import an export that doesn't exist from a file that exists, I get a runtime error.
//x.js
import { baz } from './y'
//y.js
export function foo () { return 5 }
Is there a way to have Webpack check exports in the same way it resolves files?
//webpack.config.js
module.exports = {
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015-native-modules']
}
],
}
}
I believe a runtime error in this case is correct behavior. You probably aren't getting a runtime error from the import itself, but only when you try and use it it is undefined.
A file existing or not can be easily determined by a system call during build time. However, a module exporting a given value or not can be changed at runtime - not that that is a good idea - so Webpack doesn't make a build time decision as to whether or not it should bail out.
Consider the following code:
// hats.js
var hats = undefined;
if (Math.random() > 0.5) {
hats = 'i have a hat!';
}
export const HATS = hats;
// index.js
import { HATS } from './hats';
console.log('hats is:', HATS}
Webpack can't know at build time whether or not HATS is going to exist at run time, so it won't error out when I try and import hats. However, HATS will correctly be either undefined or 'i have a hat!' when logged during execution. Similarly, if i remove the export line from hats.js, it will simply always report undefined, because Webpack cannot tell the difference after transpilation - HATS is simply undefined still. If I remove hats.js completely, Webpack knows something is definitely wrong and errors out.
As of webpack#2.1-beta15, warnings have now been added for imports of ES6 exports.
Trying to include the sax parser and running into difficulties [parser.ts].
import sax = require("sax");
export class MyParser {
//my parser code
}
When I try to use it [app.component.ts]:
import {MyParser} from './parser'
...
constructor(private http: Http, private parser: MyParser) {}
I get this error
Evaluating http://localhost:3000/sax
Which I know means SystemJS cannot find the module. Sax is installed in node_modules and listed in package.json. I've installed typings using
typings install --ambient sax
But getting lots of duplicate identifier warnings even though my tsconfig.json is excluding
"exclude": [
"node_modules",
"typings/main",
"typings/main.d.ts"
]
Lastly, isaacs uses code like this in his examples
tag.parent
tag.children
This isn't supported by the typing (d.ts).
Does anyone have a working install of sax with TS and ng2?
The error you have is at runtime. So I think that you could try to configure SystemJS this way:
<script>
System.config({
paths: {
sax: './node_modules/sax/lib/sax.js'
}
})
</script>
This way you will be able to import Sax:
import {SAXParser} from 'sax';