如何将尚未创建的文件设置为 webpack 配置的动态条目?

问题描述 投票:0回答:1

那是我的

webpack.config.js

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const fs = require('fs');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');

const generateHtmlPlugin = (chunks, filename, inject, template, templateParameters) => {
  return new HtmlWebpackPlugin({
    chunks,
    filename,
    inject,
    template,
    templateParameters
  });
}

const generateSingleBundleEntryFilePaths = async () => {
  const distDir = __dirname.split('\\') + '\\dist';
  return await fs.promises.access(distDir, fs.constants.R_OK | fs.constants.W_OK)
      .then((success) => fs.promises.readdir(distDir));
};

const multipleModulesTemplatesArray = [
  {
    chunks: ['egm_mm_wrapper_bottom_banner'],
    filename: 'egm_mm_wrapper_bottom_banner.html',
    inject: 'head',
    template: 'src/html/template.ejs',
    templateParameters: {
      bodyClass: 'egm_mm_wrapper_bottom_banner',
      htmlClass: 'egm_mm_wrapper_bottom_banner',
      initConsoleLog: 'MMWrapperBottom start'
    }
  },
  {
    chunks: ['egm_mm_wrapper_overhead_display'],
    filename: 'egm_mm_wrapper_overhead_display.html',
    inject: 'head',
    template: 'src/html/template.ejs',
    templateParameters: {
      bodyClass: 'egm_mm_wrapper_overhead_display',
      htmlClass: 'egm_mm_wrapper_overhead_display',
      initConsoleLog: 'MMWrapperOverhead start'
    }
  },
  {
    chunks: ['ilink_media_scheduler'],
    filename: 'ilink_media_scheduler.html',
    inject: 'head',
    template: 'src/html/template.ejs',
    templateParameters: {
      bodyClass: 'ilink_media_scheduler',
      htmlClass: 'ilink_media_scheduler',
      initConsoleLog: 'WMiLink.MediaScheduler start'
    }
  },
  {
    chunks: ['ilink_window_manager'],
    filename: 'ilink_window_manager.html',
    inject: 'head',
    template: 'src/html/template.ejs',
    templateParameters: {
      bodyClass: 'ilink_window_manager',
      htmlClass: 'ilink_window_manager',
      initConsoleLog: 'WMiLink.WindowManager start'
    }
  }
];

const populateHtmlPlugins = (pagesArray) => {
  const result = [];
  pagesArray.forEach(page => {
    result.push(generateHtmlPlugin(page.chunks, page.filename, page.inject, page.template, page.templateParameters));
  })
  return result;
}

const templates = populateHtmlPlugins(multipleModulesTemplatesArray);

const commonsAndVendorsConfig = {
  context: path.resolve(__dirname, '.'),
  devServer: {
    client: {
      logging: 'verbose',
      overlay: true,
    },
    static: {
      directory: path.join(__dirname, './dist'),
    },
    compress: true,
    port: 9001,
  },
  entry: [
    '../shared_libs/modules/vendors.js',
    '../shared_libs/modules/commons.js',
    './src/js/egm_mm_wrapper_commons.js',
    './src/js/ilink_commons.js',
  ],
  mode: 'production',
  module: {
    rules: [
      {
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
              '@babel/preset-env'
          ]
        },
        test: /\.js$/
      }
    ]
  },
  name: 'commons-and-vendors',
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
        terserOptions: {
          ecma: 5,
          format: {
            comments: false,
          },
          mangle: {
            toplevel: true
          },
          module: true
        },
      }),
    ]
  },
  output: {
    filename: 'commons_and_vendors.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
  performance: {
    maxEntrypointSize: 512000,
    maxAssetSize: 512000
  },
  target: 'web'
};

const multipleModulesConfig = {
  context: path.resolve(__dirname, '.'),
  devServer: {
    client: {
      logging: 'verbose',
      overlay: true,
    },
    static: {
      directory: path.join(__dirname, './dist'),
    },
    compress: true,
    port: 9001,
  },
  entry: {
    egm_mm_wrapper_bottom_banner: './modules/egm_mm_wrapper_bottom_banner.js',
    egm_mm_wrapper_overhead_display: './modules/egm_mm_wrapper_overhead_display.js',
    ilink_media_scheduler: './modules/ilink_media_scheduler.js',
    ilink_window_manager: './modules/ilink_window_manager.js'
  },
  mode: 'production',
  module: {
    rules: [
      {
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env']
          ]
        },
        test: /\.js$/
      },
      {
        exclude: /node_modules/,
        test: /\.s[ac]ss$/i,
        use: [
          'css-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.html$/i,
        loader: 'html-loader',
        options: {
          minimize: true,
        },
      },
    ]
  },
  name: 'multiple-modules',
  optimization: {
    minimize: true,
    minimizer: [
      new CssMinimizerPlugin({
        test: /\.s[ac]ss$/i
      }),
      new TerserPlugin({
        extractComments: false,
        terserOptions: {
          ecma: 5,
          format: {
            comments: false,
          },
          mangle: {
            toplevel: true
          },
          module: true
        },
      }),
    ]
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
  performance: {
    maxEntrypointSize: 512000,
    maxAssetSize: 512000
  },
  plugins: templates,
  target: 'web'
};

const singleModuleConfig = {
  context: path.resolve(__dirname, '.'),
  devServer: {
    client: {
      logging: 'verbose',
      overlay: true,
    },
    static: {
      directory: path.join(__dirname, './dist'),
    },
    compress: true,
    port: 9001,
  },
  entry: generateSingleBundleEntryFilePaths(),
  mode: 'production',
  module: {
    rules: [
      {
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env']
          ]
        },
        test: /\.js$/
      },
      {
        test: /\.html$/i,
        loader: 'html-loader',
        options: {
          minimize: true,
        },
      },
    ]
  },
  name: 'mma',
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
        terserOptions: {
          ecma: 5,
          format: {
            comments: false,
          },
          mangle: {
            toplevel: true
          },
          module: true
        },
      }),
    ]
  },
  output: {
    clean: true,
    filename: 'mma.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
  performance: {
    maxEntrypointSize: 512000,
    maxAssetSize: 512000
  },
  target: 'web'
};

module.exports = [commonsAndVendorsConfig, multipleModulesConfig, singleModuleConfig];

它使用三种配置。

首先创建供应商和通用类捆绑包,第二个创建带有注入样式的脚本,并基于

.html
模板渲染
.ejs
文件,第三个应该获取所有创建的
.html
文件和脚本并将其捆绑到单个
.js
文件中.

问题是,最后一个配置的

entry
是一个方法,它应该检查
./dist
目录是否已经创建,然后列出该目录中的所有文件,并将列表作为
string[]
返回,即数组字符串,作为
entry
.

的值

但是看起来有很多方法:

const generateSingleBundleEntryFilePaths = async () => {
  const distDir = __dirname.split('\\') + '\\dist';
  return await fs.promises.access(distDir, fs.constants.R_OK | fs.constants.W_OK)
      .then((success) => fs.promises.readdir(distDir));
};

未按预期工作:

(node:5680) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, access 'C:\Users\ar-IGT\Projects\bundles\,Users,ar-IGT,Projects,bundles\dist'
(Use `node --trace-warnings ...` to show where the warning was created)
(node:5680) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a
 promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api
/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:5680) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a 
non-zero exit code.

此警告开始时的路径甚至是错误的:

C:\Users\ar-IGT\Projects\bundles\,Users,ar-IGT,Projects,bundles\dist

不知道是什么原因造成的。

Node 没有 Observables,所以我能想到的不多,等待

./dist
目录被创建,然后用我可以用作最后一个配置条目的文件填充它。

提前致谢!

javascript node.js webpack config bundle
1个回答
0
投票

你可以尝试现代的 html-bundler-webpack-plugin

此插件允许使用条目作为模板的路径。

使用简单:

const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
module.exports = {
  plugins: [
    new HtmlBundlerPlugin({
      // relative or absolute path to templates
      entry: 'src/views/',
    }),
    preprocessor: 'ejs', // specify the template engine
  ],
  // ...
};

捆绑器插件会自动查找并渲染所有模板。

该插件支持许多开箱即用的流行模板引擎。只需安装所需的 npm 包并指定

preprocessor
与模板引擎的名称:
ejs
eta
handlebars
nunjucks

参见在浏览器中工作的示例:

Open in StackBlitz

© www.soinside.com 2019 - 2024. All rights reserved.