Включить прямую ссылку на точки входа webpack в приложение HTML?

Моя точка входа в webpack включает [hash] в имени:

entry: "index.js",
output: {
    path: "build/",
    filename: "index-[hash].js",
}

Как я могу напрямую связать эту точку входа с моим HTML-кодом приложения?

Например, мне бы хотелось, чтобы HTML-код, отправленный клиенту, включал:

<script src="build/index-41d40fe7b20ba1dce81f.js"></script>

Как я могу это сделать? Есть ли плагин, который может генерировать манифест точки входа, который мое приложение может читать и испускать соответствующие имена файлов?

Ответы

Ответ 1

html-webpack-plugin (я автор) создаст index.html для ссылки на правильное имя файла хешированного пакета.

var HtmlWebpackPlugin = require("html-webpack-plugin");
var webpackConfig = {
    entry: "index.js",
    output: {
        path: "build/",
        filename: "index-[hash].js",
    },
    plugins: [new HtmlWebpackPlugin()]
}

Это создаст build/index.html, который включает в себя ваш пакет с тегом <script>.

Ответ 2

Я только начал играть с webpack и обнаружил, что gulp подходит для записи вновь хэшированных js файлов в index.html. Если вы предпочитаете не использовать gulp, эта дискуссия о том, как что-то подобное с плагином, может немного помочь. Вот фрагмент gulpfile, который также может помочь:

var util = require('util');
var path = require('path');
var gulp = require('gulp');
var runSequence = require('run-sequence');
var rimraf = require('rimraf');
var gzip = require('gulp-gzip');
var notify = require('gulp-notify');
var gutil = require('gulp-util');
var webpack = require('webpack');
var webpackConfig = require('./client/webpack.config');
var through2 = require('through2');

gulp.task("webpack", function (cb) {
    webpack(webpackConfig, function (err, stats) {
        if (err) throw new gutil.PluginError("webpack", err);

        var jsFilename = stats.toJson().assetsByChunkName['app'];
        console.log('>>>>', jsFilename);
        // if source-maps are turned on, you'll get [ 'somefile.js', 'somefile.js.map' ]
        if (util.isArray(jsFilename)) {
            jsFilename = jsFilename.filter(function (filename) {
                return path.extname(filename).toLowerCase() === '.js'
            }).shift();
        }

        // write the hashed main.js to /dist/index.html
        gulp.src('./client/index.html')
            .on('error', handleErrors)
            .pipe(through2.obj(function (vinylFile, enc, tCb) {
                vinylFile.contents = new Buffer(String(vinylFile.contents)
                    .replace('main.js', jsFilename));
                this.push(vinylFile);
                tCb();
            }))
            .pipe(gulp.dest('./dist/'));

        cb();
    });
});

function handleErrors() {
    var args = Array.prototype.slice.call(arguments);
    notify.onError({ title: 'Error', message: '<%= error.message %>'}).apply(this, args);
    this.emit('end');
}

gulp.task('gzip-deploy', function () {
    return gulp.src('./dist/**/*')
        .on('error', handleErrors)
        .pipe(gzip())
        .pipe(gulp.dest('./dist/'));
});

gulp.task('clean', function (cb) {
    return rimraf('./dist', cb);
});

gulp.task('default', function (cb) {
    runSequence('clean', 'webpack', cb);
});

gulp.task('deploy', function (cb) {
    webpackConfig.plugins = webpackConfig.plugins = [
        new webpack.optimize.UglifyJsPlugin(),
        new webpack.DefinePlugin({
            "process.env": {
                NODE_ENV: JSON.stringify("production")
            }
        })
    ];
    webpackConfig.watch = false;
    webpackConfig.devtool = null;
    webpackConfig.output.filename = "main-[hash].js";

    runSequence('clean', 'webpack', 'gzip-deploy', cb);
});

Здесь мой webpack.config.js файл также для небольшого контекста:

var path = require('path');

module.exports = {
    context: __dirname,
    devtool: 'source-map',
    entry: {
        app: './main.js'
    },
    watch: true,
    output: {
        path: path.join(__dirname, "/../dist"),
        filename: "main.js"
    },
    module: {
        loaders: [
            { test: /\.js$/, loader: 'jsx-loader?harmony' },
            { test: /\.css$/, loader: "style-loader!css-loader" },
            { test: /\.less$/, loader: "style-loader!css-loader!less-loader" },
            { test: /\.png$/, loader: "url-loader?prefix=img/&limit=8192" },
            { test: /\.jpg$/, loader: "url-loader?prefix=img/&limit=8192" },
            { test: /\.gif$/, loader: "url-loader?prefix=img/&limit=8192" },
            { test: /\.woff$/, loader: "url-loader?prefix=font/&limit=8192" },
            { test: /\.eot$/, loader: "file-loader?prefix=font/" },
            { test: /\.ttf$/, loader: "file-loader?prefix=font/" },
            { test: /\.svg$/, loader: "file-loader?prefix=font/" }
        ]
    },
    resolve: {
        extensions: ['', '.js', '.json'],
        modulesDirectories: ['node_modules']
    },
    plugins: []
};