繁体   English   中英

如何使用 webpack 构建 JSON 文件?

[英]How do I build a JSON file with webpack?

我想以“更智能”的编程方式组装 Chrome 扩展程序使用的manifest.json文件。 我将 npm 用于我的依赖项解析,它的package.json包含一些与manifest.json文件共享的字段,包括“名称”、“描述”和“版本”。

有没有办法定义类似部分manifest.json文件的内容,其中包含所有 Chrome 特定的内容,但在适当的地方填写共享值? 我发现这在 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 加载器,但我不清楚在这种情况下如何使用它。

实际上有一个比 @user108471 更优雅的解决方案(尽管它受到它的启发),那就是使用copy-webpack-plugin 凭借其transform能力,您可以在将manifest.json复制到目的地之前,即时将所需的值添加到manifest.json

它有两个优点:

  • 它不会生成额外的不必要的manifest.js -bundle( @bronson 的解决方案也解决了这个问题)
  • require在其他一些.js文件中require manifest.json (这在我看来在语义上是倒退的)

最小设置可能是这样的:

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)
            }
         }])
   ]

}

感谢来自 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;
};

然后配置 webpack 以使用我的自定义manifest-loader

// 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.json加上从其他信息package.json 额外的manifest.js是一个脚本,它将manifest.json的内容暴露给项目中需要它的任何其他 JavaScript。 这可能不是很有用,但可以想象,Chrome 扩展程序可能希望在某个脚本中的某个地方require这样做,以友好的方式公开其中的一些信息。

我在下面的 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"),
    ]
};

应用程序/main.js

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

// Other parts of 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",
}
const manifest = {
  entry: './src/chrome_extension/dummy_index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'DELETED.js',
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      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);
            return Buffer.from(manifestString);
          },
        },
      ],
    }),
    new RemoveFilesWebpackPlugin({
      after: {
        log: false,
        include: [
          'dist/DELETED.js',
        ],
      },
    }),
  ],
  stats: 'none',
  mode: 'none',
};

我使用你的脚本已经足够了,我在 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

如果您使用的是 webpack 4,它非常简单。 我们不需要指定任何显式的 json 加载器

注意:我只是在这里将所有内容捆绑到一个 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'

试试这个包,你可以读取你的json文件,然后在用它自定义之后构建新的json。 https://github.com/webpack-contrib/json-loader

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM