【问题标题】:webpack - Creating multiple output files from template in the same way as Gruntwebpack - 以与 Grunt 相同的方式从模板创建多个输出文件
【发布时间】:2020-03-19 21:35:29
【问题描述】:

我使用 Grunt 已经有一段时间了,但现在我开始转向 webpack,因为我开始对一些 JS 进行模块化和改造。

这不是一个非常大的项目,似乎同时拥有 grunt 和 webpack 似乎有点过头了。我确实知道 webpack 不能替代 grunt,也许有一些合理的方法可以同时使用这两种方法,或者我对 webpack 的熟练程度不足以以这种方式执行每项任务。我想只用一个,但如果我不能,我将不得不同时保留它们。

所以问题是,在 Grunt(使用 grunt-replace)中,我可以从“模板”文件中将 grunt 配置中的一些变量替换为许多输出文件,因为它取自我的 gruntfile 的以下片段。

       app1: {
        options: {
          patterns: [
            {
              match: 'FOO',
              replacement: '<%= grunt.config.get("foo_1") %>'
            },
            {
              match: 'BAR',
              replacement: '<%= grunt.config.get("bar_1") %>'
            }
          ]
        },
        src: '/myTemplate.js',
        dest: '/sw-1.js'
      },
      app2: {
        options: {
          patterns: [
            {
              match: 'FOO',
              replacement: '<%= grunt.config.get("foo_2") %>'
            },
            {
              match: 'BAR',
              replacement: '<%= grunt.config.get("bar_2") %>'
            }
          ]
        },
        src: '/myTemplate.js',
        dest: '/sw-2.js'
      },

这里的“myTemplate.js”包含一些占位符,这些占位符由配置值“foo_x”、“bar_x”替换,也基于环境。

在 webpack 中,我能够使用 DefinePlugin 和 DotEnv 根据环境(即,在开发或生产中不同的 API URL)来实例化一些值。我想根据这里描述的相同原理输出一些文件。

编辑:以图形方式,

myTemplate.js 
    |
    |
 Webpack
    |
(outputs)
    |-------> sw-1.js (FOO is replaced in this file and this environment with "foo_1", the same happens with BAR).
    |
    |
    |-------> sw-1.js (FOO is replaced here in this file/environment with "foo_2".)

因此,从一个模板文件中,创建了两个输出,就像 grunt-replace 插件在发布的片段中所做的那样。

那么,是否有可能使用 webpack 来做到这一点,或者我应该继续使用我现在拥有的相同 grunt 配置来完成工作流的那一部分?

谢谢!

PS:我将 webpack.config 包括在内,以便更清楚地说明我是如何做到这一点的。

webpack.common.js

const path = require('path');
    const dotenv = require('dotenv');
    const fs = require('fs');
    const webpack = require('webpack');
    const {CleanWebpackPlugin} = require('clean-webpack-plugin');

module.exports = (env) => {
  const currentPath = path.join(__dirname);
  const basePath = currentPath + '/.env';
  const envPath = basePath + '.' + env.ENVIRONMENT;
  const finalPath = fs.existsSync(envPath) ? envPath : basePath;
  const fileEnv = dotenv.config({ path: finalPath }).parsed;

  // reduce it to a nice object, the same as before
  const envKeys = Object.keys(fileEnv).reduce((prev, next) => {
    prev[`process.env.${next}`] = JSON.stringify(fileEnv[next]);
    return prev;
  }, {});

  return {
    mode: 'development',
    entry: {
      //index: './src/index.js',
      titanpush: './src/titanpush.js',
    },
    devtool: 'inline-source-map',
    plugins: [
      new CleanWebpackPlugin(),
      new webpack.DefinePlugin(envKeys),
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist'),
    },
  };
};

webpack.dev.js

const merge = require('webpack-merge');
const common = require('./webpack.common.js');


module.exports = (env) => {
  return merge(common(env), {
    mode: 'development',
    devtool: 'inline-source-map',
    /*devServer: {
      contentBase: './dist',
    },*/
  });
};

scripts 下的 package.json 我有:

"build": "webpack --config webpack.dev.js --env.ENVIRONMENT=development"

【问题讨论】:

  • 你的问题是缺少当前的结构,以及需要的目的。正如您所写,为了“替换”代码中的占位符,您可以使用DefinePlugin
  • 正如我所说,我同时使用 Define 和 DotEnv 来根据环境实例化一些变量。但我想输出两个不同的文件也基于环境但不同的替换。它不仅仅是将几个模块捆绑在一个文件中。我将编辑问题并澄清这一点。谢谢! :D

标签: webpack gruntjs


【解决方案1】:

马上,有几种方法:

  1. 有多个 Webpack 配置,每个配置用于一组定义替换。到目前为止,这是一种更易于管理的方式来做您想做的事情,具体取决于您的配置需要多少目标文件(即定义映射)。

  2. 与1类似,使用脚本调用webpack编译器API,而不是多次命令行调用。 (示例如下)

  3. 使用更成熟的模板系统。如果您的映射足够大且足够复杂,那么投资更彻底的模板 + Web 服务器系统可能更易于维护。甚至是像 jekyll/Hugo/gatsby 这样的静态站点生成器,这取决于它们是否允许生成此类基于表的文件。


使用脚本多次运行 webpack

Webpack 可以直接在 JavaScript 中使用,无需 CLI。这样,您可以编写一个脚本,以您想要的任何方式获取和合并映射。例如,这样的事情可能会获取定义插件映射的列表并多次运行 webpack 编译步骤:

const webpack = require("webpack");
// base config without define plugin mappings, and entry setting
const yourConfig = require("./webpack.config.js");

let promises = [];

for (env in envs) {
    // update the config for every run
    const config = clone(yourConfig);
    config.plugins.push(new DefinePlugin(/* get mappings from env */));
    config.output.filename = env.outputfile;

    const compiler = webpack(config);
    let promise = new Promise((resolve, reject) => {
        compiler.run(err => {
            if (err) return reject(err);

            resolve();
        });
    });

    promises.push(promise);
}

// you'd have to add error handling here
Promise.all(promises).then(_ => {
    console.log("done");
});

// webpack.config.js
module.exports = {
    entry: "template.js",
    output: {
        filename: null,
        path: __dirname + "/dist"
    }
};

【讨论】:

  • 我需要的替换非常简单,但我希望它们易于管理,最好只使用一个工具,所以暂时我不会尝试复杂的模板解决方案(#3) .如果我理解正确,你的意思是#1,因为我已经为不同的环境构建了,我也可以定义生产需要的 2 个替换,测试需要的 2 等等?我包含了我的 webpack 配置的样子。这是我第一次使用 webpack,所以我可能需要对您为 #2 编写的代码进行一些说明。谢谢!!
猜你喜欢
  • 2014-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 2018-09-14
  • 2017-09-08
  • 2020-12-08
相关资源
最近更新 更多