Получить Webpack для вывода сгенерированного хэша в файл конфигурации

Вот стек технологий, который использует наш проект:

  • Symfony 2.8
  • Ветка 1.24
  • AngularJS 1.5
  • Веб-пакет 1.12

У нас есть проблема, заключающаяся в том, что наш файл app.min.js кэшируется, и когда мы вносим изменения, для которых требуется новый файл app.min.js, часто наши клиенты продолжают использовать кэшированный файл вместо загрузки нового файла, что в конечном итоге приводит к ошибкам и необходимости звонить в нашу службу поддержки.

Я попытался исправить это, внедрив хэш содержимого файла в HTTP-запрос, а затем заставив сервер обслуживать исходный файл с использованием правила перезаписи. Я добавил [contenthash]. к имени файла в webpack.config.js (см. ниже), но когда я запускаю Webpack, он не заменяет [contenthash] вместо создания файла с таким же именем.

module.exports = {
    output: {
        filename: 'app.min.[contenthash].js'
    }
}

Я бы хотел, чтобы это произошло:

  1. выходные файлы по-прежнему называются app.min.js и app.min.js.map
  2. сгенерированный файл карты app.min.js.map ссылается на app.min.6b1900549fed191ccbe8.js
  3. Webpack сохраняет хэш где-то в конфигурационном файле
    app_min_js_hash: '6b1900549fed191ccbe8'
    
  4. Я изменяю шаблоны Twig, чтобы включить хеш, как показано ниже:
    <script src="/dist/js/app.min.{{ app_min_js_hash }}.js"></script>
    

Итак, у меня есть несколько проблем, которые я не решил:

  1. Как заставить Webpack выводить хэш в файл конфигурации
  2. Как заставить Webpack заменить ключевое слово хешем
  3. Как заставить Webpack создавать имена файлов без хэша

Я уже знаю, как решить части rewrite и Twig.


Следуя комментариям в связанном вопросе (Загрузите пакет HtmlWebpackPlugin.[hash].js/css в базовый файл ветки), теперь у меня есть:

webpack.config.js

var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpackMajorVersion = require('webpack/package.json').version.split('.')[0];

module.exports = {
    console: true,
    name: 'js',
    entry: ['./src/base.js'],
    output: {
        path: '../web/dist/js/',
        publicPath: '/dist/js/',
        filename: 'app.min.[hash].js'
    },
    devtool: "source-map",
    resolve : {
        root : [path.join(__dirname, "src/")]
    },
    sassLoader: {
        includePaths: './src/'
    },
    resolveLoader: {
        root: __dirname+'/node_modules/',
        modulesDirectories: [""]
    },
    jshint: {
      esversion: 6
    },
    // Initialize module
    preLoaders: [],
    module: {
        preLoaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'jshint-loader',
            }
        ],
        loaders: [{
            // JS LOADER
            // Reference: https://github.com/babel/babel-loader
            // Transpile .js files using babel-loader
            // Compiles ES6 and ES7 into ES5 code
            test: /\.js$/,
            exclude: /(node_modules|bower_components)/,
            loader: 'babel',
            query: {
                presets: ['es2015']
            },
            exclude: /node_modules/
        }, {
            // ASSET LOADER
            // Reference: https://github.com/webpack/file-loader
            // Copy png, jpg, jpeg, gif, svg, woff, woff2, ttf, eot files to output
            // Rename the file using the asset hash
            // Pass along the updated reference to your code
            // You can add here any file extension you want to get copied to your output
            test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
            loader: 'file'
        }, {
            // HTML LOADER
            // Reference: https://github.com/webpack/raw-loader
            // Allow loading html through js
            test: /\.html$/,
            loader: "ngtemplate?relativeTo=" + (path.resolve(__dirname, './src/')) + "/!html"
        }, {
            test: /\.scss$/,
            loaders: ["style", "css", "sass"]
        }],
        resolve: {
            // you can now require('file') instead of require('file.coffee')
            extensions: ['', '.js', '.json', '.coffee']
        }
    },
    plugins: [
        new HtmlWebpackPlugin({
            templateContent: function(params) {
                return `
    {% block jsAssets %}
      ${params.htmlWebpackPlugin.files.js.map(
                  file => `<script src="${file}"></script>`,
                )}
    {% endblock %}

    {% block cssAssets %}
      ${params.htmlWebpackPlugin.files.css.map(
                  file => `<link rel="stylesheet" type="text/css" href="${file}">`,
                )}
    {% endblock %}`;
            },
            filename: '../../resources/templates/assets.html.twig',
            inject: false,
            // // The following settings are optional and only used for
            // // demo purposes:
            // meta: {
            //     charset: { charset: 'utf-8' },
            //     viewport: 'width=device-width, initial-scale=1'
            // },
            // minify: false
        })
    ]
};

Необходимо use сгенерированный шаблон Twig, прежде чем код Twig {{ block("jsAssets", "assets.html.twig") }} что-то сделает.

Ветка:

{% use 'HTMLBundle:Layout:assets.html.twig' %}
...
{{ block("jsAssets", "assets.html.twig") }}
...

Итак, теперь единственная оставшаяся проблема заключается в том, как сохранить имя выходного файла одинаковым каждый раз, при этом генерируя хэш. В противном случае каталог будет продолжать заполняться различными хешированными версиями (которые не совсем маленькие). Всегда нужен только последний файл. Мы используем одноэтапное развертывание, поэтому необходимость вручную переименовывать файл каждый раз, когда он создается, нарушает эту парадигму.


† Я уже знаю, что эта версия слишком старая. В краткосрочной перспективе это не изменится.


person CJ Dennis    schedule 13.06.2020    source источник


Ответы (1)


В веб-пакете 1 он назывался [hash]. Вам не нужно изобретать велосипед.

Плагин HTMLWebpack поддерживает из коробки внедрение хэша в html (даже шаблон php)

Редактировать:

Вы можете использовать хэш в качестве строки запроса:

module.exports = {
    console: true,
    name: 'js',
    entry: ['./src/base.js'],
    output: {
        path: '../web/dist/js/',
        publicPath: '/dist/js/',
        filename: 'app.min.js?[hash]'
    },
}

или вы можете добавить хэш внутри имени файла js в самом шаблоне.


new HtmlWebpackPlugin({
  templateContent: function(params) {
    return `
      {% block jsAssets %}
      ${params.htmlWebpackPlugin.files.js.map(
        file => {
          const [filename, hash] = file.split('?');
          const modifiedFileName = filename.replace('.min.js', 
          `${hash}.min.js`);
          return `<script src="${modifiedFileName}"></script>`
        }
     )}
     {% endblock %}
     `
}),
person felixmosh    schedule 13.06.2020
comment
Хорошо, [hash] отлично, за исключением того, что файл больше не связан с веб-приложением. Теперь, как мне заставить его генерировать файл с app.min.js в качестве имени файла? И как вывести хеш в файл конфигурации? - person CJ Dennis; 14.06.2020
comment
Я не уверен, о каком файле конфигурации вы говорите, но проверьте мой ответ, stackoverflow.com/questions/59609496/. он настраивает HTMLWebpackPlugin для внедрения ресурсов js/css в шаблон twig. - person felixmosh; 14.06.2020
comment
Это выглядит многообещающе. Простите, если пропустил, но куда new HtmlWebpackPlugin девается? - person CJ Dennis; 15.06.2020
comment
Итак, я догадался, что new HtmlWebpackPlugin находится в разделе plugins: [] раздела webpack.config.js, и мне удалось предотвратить сбой веб-пакета, но ваше предложение по другому вопросу {{ block("jsAssets", "assets.twig") }} ничего не выводит. - person CJ Dennis; 15.06.2020
comment
Чтобы ответить на ваш вопрос о файле конфигурации, resources/templates/assets.twig является его заменой, поэтому файл конфигурации не нужен для вашего решения. - person CJ Dennis; 15.06.2020
comment
Я придумал, как заставить работать новый шаблон Twig. Как вы можете видеть из временных меток в моих комментариях, на решение каждой проблемы уходят годы. У меня осталась только одна часть вопроса в моем ОП. - person CJ Dennis; 15.06.2020
comment
Какова недостающая часть? - person felixmosh; 15.06.2020
comment
Я отредактировал вопрос. Мне просто нужно, чтобы фактическая пара файлов была app.min.js и app.min.js.map, сохраняя при этом все остальное таким же, поэтому запрос на app.min.6b1900549fed191ccbe8.js фактически обслуживает app.min.js с сервера. - person CJ Dennis; 15.06.2020
comment
Почему вы настаиваете на том, чтобы сделать это сопоставление серверов? В настоящее время Webpack генерирует файлы twig и js с хэшами, используйте их в своей производственной среде. Что с этим не так? - person felixmosh; 15.06.2020
comment
Давайте продолжим обсуждение в чате. - person CJ Dennis; 15.06.2020