Skip to content Skip to sidebar Skip to footer

How Do I Build A Json File With Webpack?

I'd like to assemble a manifest.json file, as used by Chrome extensions, in a 'smarter,' programmatic sort of way. I'm using npm for my dependency resolution, and its package.json

Solution 1:

There is actually a more elegant solution than the one by @user108471 (although it is inspired by it), and that is to use the copy-webpack-plugin. With its transform ability, you can add the desired values to the manifest.json on the fly before copying it to its destination.

It has two advantages:

  • it doesn't generate an extra unnecessary manifest.js-bundle (@bronson's solution also fixes this)
  • you don't need to require the manifest.json in some other .js-file (which would seem semantically backwards to me)

A minimal setup could be this:

webpack.config.js

// you can just require .json, saves the 'fs'-hasslelet package = require('./package.json');

functionmodify(buffer) {
   // copy-webpack-plugin passes a buffervar manifest = JSON.parse(buffer.toString());

   // make any modifications you like, such as
   manifest.version = package.version;

   // pretty print to JSON with two spaces
   manifest_JSON = JSON.stringify(manifest, null, 2);
   return manifest_JSON;
}


module.exports = {

   // ...plugins: [
      newCopyWebpackPlugin([
         {
            from: "./src/manifest.json",
            to:   "./dist/manifest.json",
            transform (content, path) {
                returnmodify(content)
            }
         }])
   ]

}

Solution 2:

Credit to Sean Larkin from the Webpack project for reaching out to me and helping me figure out how to get this done. I needed to create a custom loader to handle reading the existing manifest.json and adding my fields of interest to it.

// File: src/manifest-loader.jsconst fs = require('fs');

// A loader to transform a partial manifest.json file into a complete// manifest.json file by adding entries from an NPM package.json.module.exports = function(source) {
  const pkg = JSON.parse(fs.readFileSync('./package.json'));
  const merged = Object.assign({}, JSON.parse(source), {
    'name': pkg.name,
    'description': pkg.description,
    'version': pkg.version,
    'author': pkg.author,
    'homepage_url': pkg.homepage,
  });
  const mergedJson = JSON.stringify(merged);
  // In Webpack, loaders ultimately produce JavaScript. In order to produce// another file type (like JSON), it needs to be emitted separately.this.emitFile('manifest.json', mergedJson);
  // Return the processed JSON to be used by the next item in the loader chain.return mergedJson;
};

Then configure webpack to use my custom manifest-loader.

// File: webpack.config.jsconst path = require('path');

module.exports = {
  // Tell Webpack where to find our custom loader (in the "src" directory).resolveLoader: {
    modules: [path.resolve(__dirname, "src"), "node_modules"]
  },

  // The path to the incomplete manifest.json file.entry: "./manifest.json",
  output: {
    // Where the newly built manifest.json will go.path: path.resolve(__dirname, 'dist'),
    // This file probably won't actually be used by anything.filename: "manifest.js",
  },

  module: {
    rules: [
      {
        // Only apply these loaders to manifest.json.test: /manifest.json$/,
        // Loaders are applied in reverse order.use: [
          // Second: JSON -> JS"json-loader",
          // First: partial manifest.json -> complete manifest.json"manifest-loader",
        ]
      }
    ]
  }
};

The result, when running Webpack, is a dist/ directory containing manifest.js and manifest.json, with manifest.json containing everything from the original, top-level manifest.json plus the additional info from package.json. The extra manifest.js is a script that exposes the contents of manifest.json to any other JavaScript in the project that wants it. This is probably not too useful, but a Chrome extension might conceivably want to require this in a script somewhere to expose some of this information in a friendly way.

Solution 3:

My solution in Webpack 4 below. It's a generic solution for generating json files using Webpack loaders, but it works well for manifest.json files as well.

webpack.config.js

constExtractTextPlugin = require("extract-text-webpack-plugin");
const resolve = require("path").resolve;

module.exports = {
    entry: {
        entry: resolve(__dirname, "app/main.js"),
    },
    module: {
        rules: [
            {
                test: /manifest\.js$/,
                use: ExtractTextPlugin.extract({
                    use: []  // Empty array on purpose.
                })
            }
        ],
        {
            test: /\.png$/,
            use: [{
                loader: "file-loader",
                options: {
                    context: resolve(__dirname, "app"),
                    name: "[path][name].[ext]",
                    publicPath: "/",
                }
            }]
        }
    },
    output: {
        filename: "[name].js",
        path: resolve(__dirname, 'dist'),
    },
    plugins: [
        new webpack.EnvironmentPlugin(["npm_package_version"]),  // automagically populated by webpack, available as process.env.npm_package_version in loaded files.newExtractTextPlugin("manifest.json"),
    ]
};

app/main.js

const manifest = require('./manifest.js');

// Other parts of app …

app/manifest.js

const icon = require('./icon.png');  

const manifestData = {  
    icon: {"128": icon},  // icon.png will be in the emitted files, yay!version: process.env.npm_package_version,  // See webpack.config.js plugins// other manifest data …
};

// Whatever string you output here will be emitted as manifest.json:module.exports = JSON.stringify(manifestData, null, 2);

package.json dependencies

{
    "extract-text-webpack-plugin": "4.0.0-beta.0",
    "file-loader": "1.1.11",
    "webpack": "4.12.0",
}

Solution 4:

const manifest = {
  entry: './src/chrome_extension/dummy_index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'DELETED.js',
  },
  plugins: [
    newCleanWebpackPlugin(),
    newCopyWebpackPlugin({
      patterns: [
        {from: 'LICENSE.md'},
        {from: 'assets/img/icon.png', to: `${ASSETS_PATH}/icon.png`},
        {from: 'src/chrome_extension/manifest.json',
          transform: function(manifestBuffer, path) {
            const manifestString = manifestBuffer.toString()
                .replace(/\$\{OPTIONS_PAGE_PATH\}/g, OPTIONS_PAGE_PATH)
                .replace(/\$\{CONTENT_SCRIPT_PATH\}/g, CONTENT_SCRIPT_PATH)
                .replace(/\$\{ASSETS_PATH\}/g, ASSETS_PATH);
            returnBuffer.from(manifestString);
          },
        },
      ],
    }),
    newRemoveFilesWebpackPlugin({
      after: {
        log: false,
        include: [
          'dist/DELETED.js',
        ],
      },
    }),
  ],
  stats: 'none',
  mode: 'none',
};

Solution 5:

I was using your script enough that I published a somewhat modified version of it on NPM: https://github.com/bronson/manifest-package-loader

Hope it's as easy as yarn add -D manifest-package-loader and updating your webpack.config.js.

Coincidentally, just this morning I ran across chem-loader, which might also work: https://github.com/mrmisterman/chem-loader

Post a Comment for "How Do I Build A Json File With Webpack?"