web-dev-qa-db-ja.com

JSとCSSを別々のHTMLファイルに分割するにはどうすればよいですか?

HtmlWebpackPluginを使用して、JSスクリプトタグを1つのファイルに分割し、CSSリンクタグを別のファイルに分割する必要があるという非常に具体的な要件があります。

現時点では、bothスクリプトタグとリンクタグがbothファイルに入っています。それらを別々に行う方法はありますか?

これが私の現在のWebpackファイルです:

import webpack from 'webpack'
import path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import autoprefixer from 'autoprefixer'

const extractCSS = new ExtractTextPlugin({
  filename: 'css/app.bundle.css',
  allChunks: true
})

const createCSSfile = new HtmlWebpackPlugin({
  chunks: ['app'],
  minify: {
    collapseWhitespace: true
  },
  hash: true,
  template: 'src/ejs/css.ejs',
  filename: 'templates/css.php'
})

const createJSfile = new HtmlWebpackPlugin({
  chunks: ['app'],
  minify: {
    collapseWhitespace: true
  },
  hash: true,
  template: 'src/ejs/js.ejs',
  filename: 'templates/js.php'
})

const config = {
  entry: {
    'app': [
      path.resolve(__dirname, 'src/js/app.js'),
      path.resolve(__dirname, 'src/scss/app.scss')
    ]
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist',
    filename: 'js/app.bundle.js',
    sourceMapFilename: 'js/app.bundle.map'
  },
  devtool: 'source-map',
  watch: true,
  watchOptions: {
    ignored: /node_modules/,
    aggregateTimeout: 300,
    poll: 1000
  },
  module: {
    rules: [
      {
        test: /\.(png|gif|jpg|jpeg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '/images/[name].[ext]'
            }
          }
        ]
      },
      {
        test: /\.(eot|ttf|woff|woff2|otf)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '/fonts/[name].[ext]'
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: [require('@babel/plugin-proposal-object-rest-spread')]
          }
        }
      },
      {
        test: /\.scss$/,
        use: extractCSS.extract([
          {
            loader: 'css-loader'
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins () {
                return [
                  autoprefixer({
                    browsers: [
                      'last 2 versions',
                      'Safari >= 8',
                      'Explorer >= 9',
                      'Android >= 4'
                    ]
                  })
                ]
              }
            }
          },
          {
            loader: 'sass-loader'
          }
        ])
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'js/app.common',
      filename: 'js/app.common.js',
      minChunks: 2
    }),
    createCSSfile,
    createJSfile,
    extractCSS
  ]
}

export default config

.ejsファイルは空であり、.phpファイル内に以下を生成します。

<head><link href="/dist/css/app.bundle.css?bdba9ec6846a7d92d61f" rel="stylesheet"></head><script type="text/javascript" src="/dist/js/app.bundle.js?bdba9ec6846a7d92d61f"></script>

それらを分離する方法はありますか?

また、CSSリンクにheadタグが挿入されていることに気付きました。これを止める方法はありますか?

15

@mootrichardの助けを借りて、私は必要な答えを得ることができました。

実行する手順:

  1. JSとCSSをそれぞれのエントリポイントに分離します。
  2. HtmlWebpackPluginconfigsでinject: falseを設定して、Webpackがこれを実行しないようにします。
  3. チャンク内の「common」を参照して、共通のJSファイルをテンプレートで使用できるようにします。
  4. ファイル配列をループするように.ejsテンプレートを構成します。

webpack.config.babel.js

import webpack from 'webpack'
import path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import autoprefixer from 'autoprefixer'

const extractCSS = new ExtractTextPlugin({
  filename: 'css/app.bundle.css',
  allChunks: true
})

const createCSSfile = new HtmlWebpackPlugin({
  chunks: ['css'],
  excludeChunks: ['js', 'common'],
  minify: {
    collapseWhitespace: true,
    preserveLineBreaks: true,
    removeComments: true
  },
  inject: false,
  hash: true,
  template: 'src/ejs/css.ejs',
  filename: 'templates/css.php'
})

const createJSfile = new HtmlWebpackPlugin({
  chunks: ['js', 'common'],
  excludeChunks: ['css'],
  minify: {
    collapseWhitespace: true,
    preserveLineBreaks: true,
    removeComments: true
  },
  inject: false,
  hash: true,
  template: 'src/ejs/js.ejs',
  filename: 'templates/js.php'
})

const config = {
  entry: {
    'css': [
      path.resolve(__dirname, 'src/scss/app.scss')
    ],
    'js': [
      path.resolve(__dirname, 'src/js/app.js')
    ]
  },
  output: {
    path: path.resolve(__dirname, 'build'),
    publicPath: '/build',
    filename: 'js/app.bundle.js',
    sourceMapFilename: 'js/app.bundle.map'
  },
  devtool: 'source-map',
  watch: true,
  watchOptions: {
    ignored: /node_modules/,
    aggregateTimeout: 300,
    poll: 1000
  },
  module: {
    rules: [
      {
        test: /\.(png|gif|jpg|jpeg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '/images/[name].[ext]'
            }
          }
        ]
      },
      {
        test: /\.(eot|ttf|woff|woff2|otf)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '/fonts/[name].[ext]'
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: [require('@babel/plugin-proposal-object-rest-spread')]
          }
        }
      },
      {
        test: /\.scss$/,
        use: extractCSS.extract([
          {
            loader: 'css-loader'
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins () {
                return [
                  autoprefixer({
                    browsers: [
                      'last 2 versions',
                      'Safari >= 8',
                      'Explorer >= 9',
                      'Android >= 4'
                    ]
                  })
                ]
              }
            }
          },
          {
            loader: 'sass-loader'
          }
        ])
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'common',
      filename: 'js/app.common.js',
      minChunks: 2
    }),
    createCSSfile,
    createJSfile,
    extractCSS
  ]
}

export default config

js.ejs

<% for (let i = 0; i < htmlWebpackPlugin.files.js.length; i++) { %>
  <script src="<%= htmlWebpackPlugin.files.js[i] %>"></script>
<% } %>

css.ejs

<% for (let i = 0; i < htmlWebpackPlugin.files.css.length; i++) { %>
  <link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[i] %>">
<% } %>

これが将来誰かを助けるようになることを願っています。

このアプローチの利点

JSとCSSを実際の別々のファイルに分離する必要がある理由は、WordPressで使用するためでした。ここでは、テンプレートには継承元の「マスター」テンプレートの概念がなく、代わりに基本的なfooterおよびheaderが含まれます。

したがって、WordPressを使用している場合、これはかなり良いアプローチです。

12

内容の異なる個別のファイルが必要なため、エントリポイントを分割し、チャンクをフィルタリングすることをお勧めします。

HtmlWebpackPluginの両方のインスタンスで、CSSとJSの両方を含むchunks: ['app']を設定しています。

あなたは次のようなものを持つことができます:

entry: {
  'js': [
     path.resolve(__dirname, 'src/js/app.js')
  ],
  'css': [
     path.resolve(__dirname, 'src/scss/app.scss')
  ]
},

次に、次のことができます。

const createCSSfile = new HtmlWebpackPlugin({
    chunks: ['css'],
    minify: {
        collapseWhitespace: true
    },
    hash: true,
    inject: false,
    template: 'src/ejs/css.ejs',
    filename: 'templates/css.php'
})

const createJSfile = new HtmlWebpackPlugin({
    chunks: ['js'],
    minify: {
        collapseWhitespace: true
    },
    hash: true,
    inject: false,
    template: 'src/ejs/js.ejs',
    filename: 'templates/js.php'
})

<head>に含まれているCSSについては、HTMLファイルの作成に独自のカスタムテンプレートを使用しているため、inject: falseを設定する必要があります。 https://github.com/jantimon/html-webpack-plugin#configuration

6
mootrichard