web-dev-qa-db-ja.com

WebpackでJSONファイルを作成するにはどうすればよいですか?

Chrome拡張機能で使用されるmanifest.jsonファイルを「スマートな」プログラム的な方法でアセンブルしたい。依存関係の解決にnpmを使用している。 package.jsonには、「名前」、「説明」、「バージョン」など、manifest.jsonファイルとの共有フィールドがいくつか含まれています。

すべてのChrome固有のものを含む、部分的なmanifest.jsonファイルのようなものを定義する方法はありますか?これはGulpではかなり単純であることがわかりました。

var gulp = require('gulp');
var fs = require('fs');
var jeditor = require('gulp-json-editor');

gulp.task('manifest', function() {
    var pkg = JSON.parse(fs.readFileSync('./package.json'));
    gulp.src('./manifest.json')
      .pipe(jeditor({
        'name': pkg.name,
        'description': pkg.description,
        'version': pkg.version,
        'author': pkg.author,
        'homepage_url': pkg.homepage,
      }))
      .pipe(gulp.dest("./dist"));
});

この目的のために設計されたnpmパッケージがそこにあるとしても、誰かがこのようなことが一般的にどのように行われるかを私に説明できますか? Webpack 2には組み込みのjsonローダーがあることは知っていますが、このような場合にどのように使用されるかはわかりません。

15
user108471

WebpackプロジェクトのSean Larkinが私に連絡を取り、これを行う方法を理解してくれたことを感謝します。既存のmanifest.jsonの読み取りと、対象となるフィールドの追加を処理するカスタムローダーを作成する必要がありました。

// File: src/manifest-loader.js

const 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;
};

次に、カスタムmanifest-loaderを使用するようにwebpackを構成します。

// File: webpack.config.js

const 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",
        ]
      }
    ]
  }
};

Webpackを実行すると、結果はdist/ディレクトリにmanifest.jsmanifest.jsonが含まれ、manifest.jsonには元のトップレベルのmanifest.jsonpackage.jsonからの追加情報。追加のmanifest.jsは、manifest.jsonの内容を、それを必要とするプロジェクト内の他のJavaScriptに公開するスクリプトです。これはおそらくあまり役​​には立ちませんが、Chrome拡張機能はスクリプトのどこかでこれをrequireにして、この情報の一部をわかりやすい方法で公開したい場合があります。

7
user108471

@ user108471によるソリューションよりも実際にはよりエレガントなソリューションがあり(それに触発されていますが)、それは copy-webpack-plugin を使用することです。 transform 機能により、目的の値をコピー先にコピーする前に、オンザフライでmanifest.jsonに必要な値を追加できます。

これには2つの利点があります。

  • 余分な不要なmanifest.js- bundleは生成されません( @ bronsonのソリューション もこれを修正します)
  • 他のmanifest.jsonファイルでrequire.jsを実行する必要はありません(意味的に後方に見えるようになります)

最小限の設定は次のようになります:

webpack.config.js

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

function modify(buffer) {
   // copy-webpack-plugin passes a buffer
   var 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: [
      new CopyWebpackPlugin([
         {
            from: "./src/manifest.json",
            to:   "./dist/manifest.json",
            transform (content, path) {
                return modify(content)
            }
         }])
   ]

}
11
Rens Baardman

以下のWebpack 4での私の解決策。これは、Webpackローダーを使用してjsonファイルを生成するための一般的なソリューションですが、manifest.jsonファイルでも同様に機能します。

webpack.config.js

const ExtractTextPlugin = 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.
        new ExtractTextPlugin("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の依存関係

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

Webpack 4を使用している場合は、非常に簡単です。明示的なjsonローダーを指定する必要はありません

注:ここではすべてを1つのhtmlファイルにバンドルしていますが、webpack.config.jsファイルにjsonローダーがないことがわかります

webpack.config.js

const HtmlWebPackPlugin = require("html-webpack-plugin");
 const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');

module.exports = {
 module: {
rules: [
  {
    test: /\.js$/,
    exclude: [/node_modules/],
    use: [{
      loader: 'babel-loader'
    }],
  },
  {
    test: /\.css$/,
    use: ["style-loader", "css-loader"]
  },
  {
      test: /\.ico$/,
      use: ["file-loader"]
  },
  {
    test: /\.html$/,
    use: [
      {
        loader: "html-loader",
        options: { minimize: true }
      }
    ]
  }
],
},
 plugins: [
new HtmlWebPackPlugin({
  template: "./src/index.html",
  filename: "./index.html",
  inlineSource: '.(js|css)$'
}),
new HtmlWebpackInlineSourcePlugin(),
],
devServer: {
  compress: true,
  disableHostCheck: true,
  }
}

私のapp.jsでは私はちょうど使用します

import data from './data/data.json'
0
user1707141

私はあなたのスクリプトを十分に使っていたので、NPMにそれの多少変更されたバージョンを公開しました: https://github.com/bronson/manifest-package-loader

yarn add -D manifest-package-loaderと同じくらい簡単で、webpack.config.jsを更新してください。

偶然にも、今朝ちょうど私はchem-loaderに遭遇しましたが、これも機能する可能性があります: https://github.com/mrmisterman/chem-loader

0
bronson