1

My Angular app is configured with a JSON file. I was loading it via an HTTP GET, but recently decided to include it directly by adding JSON support to TypeScript with a Definition file:

declare module "*.json" {
    const value: any;
    export default value;
}

And then importing it where needed:

import * as config from '../config.json';

This works great; config is the JSON object itself.

The problem is that I'm bundling with Webpack and I want the JSON file to be in the package, but not bundled with anything else, that is, config.json should be its own file in the package, rather than being bundled with other files.

I tried doing this with file-loader and move-file-loader:

module: {                                                                    
    rules: [  
    // ...  
    {                                                                        
       test: /\.json$/,                                                       
       loader: 'file-loader?name=[name].json'                                 
    }                                                      
    // OR                                                                    
    {                                                                
        test: /\.json$/,                                                     
        loader: "move-file-loader?name=[name].json!json-loader"              
    }
    // ...
    ]
}

This prevents the JSON file from being bundled and places it where I want it in the package, but it also makes config become the relative path to the JSON file, i.e., "./config.json", rather than the JSON object itself.

Any thoughts on why this might be?

1 Answer 1

1

Apparently file-loader emits a path to where the file was loaded, rather than the file contents itself. So

import * as config from '../config.json';

making config into a string containing a path to the file is the correct behavior.

As far as move-file-loader is concerned, since I'm using it with json-loader, the contents of the "moved" file is actually a TypeScript module definition, and it seems to still be loading a bundled version of the file rather than the "copied" version.

These insights lead me to the following solution: First of all, we'll copy JSON files using file-loader in the Webpack config:

module: {                                                                    
    rules: [  
    // ...  
    {                                                                        
       test: /\.json$/,                                                       
       loader: 'file-loader?name=[name].json'                                 
    }
    // ...
    ]
}

Then we'll import the file path emitted by file-loader using TypeScript's require syntax

const configFile = require('../config.json');

This import method doesn't require the JSON definition file I mention in my question.

Lastly, we can load the file from its file-loader path via an HTTP GET:

http.get(configFile).map(res => res.json()).catch((error: any): any => {
    // ...
}).subscribe(config => {
    // ...
});

where config is the parsed contents of the JSON file.

I won't mark this as the answer right away in case someone knows how to get this working without HTTP.

Sign up to request clarification or add additional context in comments.

2 Comments

I try to follow your answer but webpack build fails with Module parse failed: Unexpected token e in JSON at position 0 while parsing near 'export default __web...' DO you have any ideas to what it could be related?
@DicBrus I can't be sure without seeing your code but it looks like there's a syntax error in your JSON file. Honestly, I ended up switching back to loading my JSON via HTTP GET because the code was cleaner and easier to maintain.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.