#javascript #angularjs #webpack
#javascript #angularjs #webpack
Вопрос:
Я перенес наше приложение AngularJS на использование webpack — до того, как оно использовало gulp. в версии gulp я использовал плагин rev для обновления всех файлов (css, js и html), однако в режиме webpack я не могу найти способ добавить хэш к html-шаблонам, что вызывает проблемы, поскольку браузер обслуживает старые HTML-файлы. Как это можно исправить? ниже приведен файл webpack conf
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const OpenBrowserPlugin = require('open-browser-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const RemoteServer = process.env.REMOTE_SERVER;
const appEnv = process.env.NODE_ENV || 'development';
const isProduction = appEnv === 'production';
const patterns = require('../server/src/main/resources/regex.json');
const appPath = path.join(__dirname, 'app');
const buildPath = path.join(__dirname, 'artifacts');
const config = {
entry: [path.join(appPath, 'index.js')],
output: {
path: buildPath,
filename: '[name].[hash].js',
chunkFilename: '[name].[hash].js'
},
resolve: {
modules: ['node_modules', appPath],
alias: {
'ui-select-css': path.resolve('./node_modules/ui-select/dist/select.css'),
fonts: path.resolve(__dirname, 'assets/fonts')
}
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
emitWarning: true,
quiet: true
}
},
{
test: /.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'resolve-url-loader'
]
},
{
test: /.less$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader', options: {
url: false,
sourceMap: true
}
}, {
loader: 'less-loader', options: {
relativeUrls: false,
sourceMap: true
}
}]
},
{
test: /.(jpe?g|png|gif)(?.*)?$/i,
use: [{
loader: 'file-loader',
options: {name: '[path][name].[hash].[ext]'}
}]
},
{
test: /.woff(2)?(?v=[0-9].[0-9].[0-9])?$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
},
{
test: /.ttf(?v=d .d .d )?$/,
use: [
{
loader: 'url-loader',
options: {limit: 10000, mimetype: 'application/octet-stream'}
}
]
},
{
test: /.eot(?v=d .d .d )?$/,
use: [
{
loader: 'file-loader'
}
]
},
{
test: /.svg$/i,
loader: 'raw-loader'
},
{
test: require.resolve('angular'),
use: [
{loader: 'expose-loader', options: 'angular'},
]
},
{
test: require.resolve('jquery'),
use: [
{loader: 'expose-loader', options: '$'},
{loader: 'expose-loader', options: 'jQuery'},
]
},
{
test: require.resolve('lodash'),
use: [
{loader: 'expose-loader', options: '_'},
]
},
{
test: require.resolve('moment'),
use: [
{loader: 'expose-loader', options: 'moment'},
]
},
{
test: /.html$/,
use: [{
loader: 'raw-loader',
options: {name: '[path][name].[hash].[ext]'}
}]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(appPath, 'index.html')
}),
new webpack.DefinePlugin({
INJECT_REGEX_HERE: JSON.stringify(patterns)
}),
new CopyWebpackPlugin([
{from: 'app/images', to: 'assets/images'},
{from: 'app/fonts', to: 'assets/fonts'},
{from: 'app/templates', to: 'assets/templates'},
{from: 'app/silent-callback.html', to: 'silent-callback.html'},
{from: 'node_modules/font-awesome/css', to: 'assets/font-awesome/css'},
{from: 'node_modules/font-awesome/fonts', to: 'assets/font-awesome/fonts'},
{from: 'node_modules/angular-ui-grid/fonts', to: 'assets/fonts'},
{from: 'node_modules/d3/d3.min.js', to: 'assets/d3'}
]),
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
new OpenBrowserPlugin({url: 'http://localhost:1337'})
],
devtool: isProduction ? 'source-map' : 'inline-source-map',
devServer: {
port: 1337
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
if (RemoteServer) {
console.log('running with remote server', RemoteServer);
config.devServer.proxy = {
'/occm/*': 'http://' RemoteServer
};
}
if (isProduction) {
config.plugins.push(
new CleanWebpackPlugin(buildPath)
);
}
module.exports = config;
Комментарии:
1. Вы нашли решение для этого? Я ищу то же самое
2. В качестве опции вы можете встроить все html-шаблоны в js. Это то, что мы делаем в нашем приложении.
3. @PetrAveryanov как вы обрабатываете ngIncludes (если они у вас есть)?
4. У нас есть только «file-local» ng-includes, и проблем нет. (Мы помещаем глобальные шаблоны непосредственно в templateCache)
Ответ №1:
Одним из основных преимуществ использования Webpack является сокращение количества запросов, которые браузер должен выполнять для рендеринга вашего приложения, и ускорение запуска вашего приложения. Для достижения этого он группирует связанные ресурсы вместе в «куски», которые загружаются вместе в одном запросе. Отдельная загрузка требуемых отдельных файлов, таких как HTML-шаблоны (без конкретной причины), может рассматриваться здесь как антишаблон.
Наилучшей практикой является группирование всего связанного кода JS, HTML и CSS в один большой пакет, который загружается один раз, иногда (для больших приложений) имея второй пакет ‘vendor’ для кода из node_modules, что ускоряет разработку, потому что этот фрагмент не будет меняться так часто.
Альтернативное решение:
Итак, в вашем случае, если нет конкретной причины для хранения вещей отдельно (о чем вы не писали), я бы скорее рекомендовал обслуживать HTML вместе с управляющим кодом в одном блоке, вместо того, чтобы загружать HTML-файлы отдельно.
Хорошей и простой отправной точкой было бы создать всего два блока. Замените весь ваш блок оптимизации следующим кодом:
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\/]node_modules[\/]/,
name: 'vendor',
chunks: 'all'
}
}
}
},
Это создаст два блока: один основной блок для всех ваших JS и HTML-файлов и другой, явно для всего, что находится в папке node_modules.
Таким образом, вам больше не придется беспокоиться о кешах браузера для HTML-файлов, потому что они встроены в ваш основной блок, и, как преимущество, ваше приложение запустится быстрее.
Комментарии:
1. Суть в том, что webpack обработает это за вас автоматически, вам не нужно создавать хэши самостоятельно.
Ответ №2:
Я делал аналогичную миграцию пару лет назад, и мне не понадобилось решение такого типа. Моей целью было инкапсулировать каждый компонент в виде модуля, а затем отложить загрузку настолько, насколько это возможно.
// webpack config
{
test: /.html$/,
use: ['html-loader'],
},
Затем в каждом компоненте мне просто требуются стили и шаблон, подобные:
require('./_proposal-page.scss');
(function() {
'use strict';
angular.module('component.myComponent', []).component('myComponent', {
template: require('./proposal-page.html'),
controller: MyController,
});
/** @ngInject */
function MyController($log) {
const $ctrl = this;
$ctrl.$onInit = function() {
$log.log('$onInit myComponent');
}
}
})();
if (typeof module !== 'undefined' amp;amp; typeof exports !== 'undefined' amp;amp; module.exports === exports) {
module.exports = 'component.myComponent';
}
Webpack определяет требования и экспортирует каждый .html
файл как модуль, он работает без сбоев.