Ionic 2 меняет имя main.js (настройка выходного имени файла webpack.js)
У нас есть приложение Ionic 2, которое развернуто как в сети, так и в Интернете. При строительстве я использую npm run build --prod --release
, Это просто обертывания ionic build.
Я пытаюсь обновить наш процесс сборки, чтобы иметь возможность заменить по умолчанию main.js.
то есть в index.html
Поэтому я хочу иметь возможность изменить этот файл с:
<script src="build/main.js"></script>
с (автоматически сгенерированный хеш)
<script src="build/main.7b297e8f7d1c2760a1bc.js"></script>
Шаг 1 - создать файл. Мне удалось успешно сгенерировать нужный файл каждой сборки с помощью параметра вывода web.filename.
module.exports = {
entry: [process.env.IONIC_APP_ENTRY_POINT, './web.config', './src/ai.min.js'],
output: {
path: '{{BUILD}}',
filename: '[name].[chunkhash].js',
Когда я собираю, я вижу, что он правильно генерирует исходный файл, но вскоре после завершения ionic build
не удается с сообщением о невозможности найти build/main.js.
Это было исходное имя файла, поэтому я думаю, что мне нужно как-то сообщить, что ionic меняет имя файла main.js.
Ошибка:
[11:00:32] build prod failed: ENOENT: no such file or directory, open
'/Users/work/client/www/build/main.js'
[11:00:32] ionic-app-script task: "build"
[11:00:32] Error: ENOENT: no such file or directory, open '/Users/work/client/www/build/main.js'
Я не уверен, как обновить ionic build
чтобы он знал, как искать динамически генерируемое имя файла main.js.
3 ответа
РЕДАКТИРОВАТЬ
Гораздо более простое решение, которое с гораздо меньшей вероятностью сломается, когда ionic будет иметь большие обновления.
https://gist.github.com/haydenbr/7df417a8678efc404c820c61b6ffdd24
Так что кеш разорится с ионным. Это хакерское решение, но пока оно работает. Проблема в том, что система ионных сборок иногда слишком много абстрагируется. Еще в октябре был задан вопрос о том, существует ли способ реализовать очистку кэша. Ионная команда ответила, что они могли бы рассмотреть это в будущем, но с тех пор там не было никакой активности. Вот проблема GitHub.
Поэтому я покажу все изменения в config и package.json для webpack, а затем объясню все.
Раздел config вашего package.json должен выглядеть следующим образом.
"config": {
"ionic_webpack": "./webpack.config.js",
"ionic_source_map_type": "source-map",
"ionic_uglifyjs": "./www/uglifyjs.config.json"
}
Для вашей конфигурации веб-пакета ваши вход и выход могут оставаться неизменными. Убедитесь, что вам потребуются следующие модули, а затем вы захотите добавить следующие плагины:
var path = require('path'),
fs = require('fs'),
ManifestPlugin = require('webpack-manifest-plugin'),
HtmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
new HtmlWebpackPlugin({
filename: './../index.html',
inject: 'body',
template: './src/index.html',
title: 'My App',
}),
new ManifestPlugin(),
updateFileName
]
где updateFileName
как следует
function updateFileName() {
this.plugin("done", function() {
var manifest = require(process.env.IONIC_BUILD_DIR + '/manifest.json'),
fileName = process.env.IONIC_OUTPUT_JS_FILE_NAME;
updateUglifyConfig(fileName, manifest);
process.env.IONIC_OUTPUT_JS_FILE_NAME = manifest[fileName];
});
}
function updateUglifyConfig(fileName, manifest) {
var uglifyConfig = {
sourceFile: manifest[fileName],
destFileName: manifest[fileName],
inSourceMap: manifest[fileName + '.map'],
outSourceMap: manifest[fileName + '.map'],
mangle: true,
compress: true,
comments: true
};
// we're writing this to www because it's specific to the current
// build and we don't want to commit it
fs.writeFileSync(
path.join(__dirname, 'www', 'uglifyjs.config.json'),
JSON.stringify(uglifyConfig, null, 4)
);
}
Так что на самом деле здесь происходит? Во-первых, в файле package.json нам нужно сгенерировать новый конфигурационный файл uglify для процесса ионной сборки. Вы можете изменить имя файла в середине сборки и до тех пор, пока вы назначаете новое имя process.env.IONIC_OUTPUT_JS_FILE_NAME
тогда остальная часть сборки будет работать нормально, за исключением того, что шаг uglify по-прежнему будет искать имя по умолчанию, main.js
, Мы увидим, как мы создадим это ниже.
Теперь для трех плагинов мы добавляем.
Первый делает немного магии. Это действительно настраивается. Как это установлено, он берет по умолчанию index.html, устанавливает заголовок, вставляет <script>
тег для вывода JavaScript, а затем записать его туда, где вы указали в свойстве filename. Если вы используете файл index.html по умолчанию, который поставляется из ионного начального приложения, то все, что вам нужно сделать, это избавиться от <script src="build/main.js"></script>
и он автоматически вставит в них новую ссылку для имени файла с хешем в нем. Документы здесь.
Следующий плагин выводит для нас файл манифеста, чтобы мы могли знать, какое имя файла у хэша. По умолчанию он выводит его в www/build/
, Документы здесь.
Следующий плагин - это то, что назначает новое имя файла для process.env.IONIC_OUTPUT_JS_FILE_NAME и генерирует новую конфигурацию uglify для нас. В основном мы берем выдаваемый манифест, записываем новую конфигурацию uglify в каталог www, а затем присваиваем имя нового файла из того, что мы получили из манифеста.
Так что вот и все. Если вы не хотите, чтобы очистка кэша выполнялась с помощью dev, сохраните плагин html, избавьтесь от двух других, а затем измените имя выходного файла обратно на process.env.IONIC_OUTPUT_JS_FILE_NAME
, Если вы сделаете это, вам не нужно ссылаться на основной файл JS в вашем src/index.html
совсем. Это будет вставлено, будь то бегущий разработчик или прод. Чтобы узнать больше об использовании различных настроек веб-пакетов для разных сред, проверьте это.
ОБНОВИТЬ:
Для ионной 3:
- Убедитесь, что у вас есть эти настройки в
compilerOptions
вашейtsconfig
:
"module": "es2015", "target": "es5"
npm i cheerio --save-dev
- в вашем конфиге добавьте
var cheerio = require('cheerio')
- Избавьтесь от плагина Webpack Manifest.
+ Изменить
updateFileName
к следующему:function updateFileName() { this.plugin("done", function(stats) { var buildOutput = stats.toJson()['assetsByChunkName']['main'], fileName = process.env.IONIC_OUTPUT_JS_FILE_NAME, manifest = { [fileName]: buildOutput[0], [fileName + '.map']: buildOutput[1] }; updateUglifyConfig(fileName, manifest); process.env.IONIC_OUTPUT_JS_FILE_NAME = manifest[fileName]; console.log('IONIC_OUTPUT_JS_FILE_NAME', process.env.IONIC_OUTPUT_JS_FILE_NAME); }); }
Избавьтесь от плагина Html Webpack
Вместо плагина html поместите следующую функцию в массив плагинов в конфигурации вашего веб-пакета:
function updateIndexHTML() { this.plugin("done", function(stats) { var buildOutput = stats.toJson()['assetsByChunkName']['main'], outputFileName = buildOutput[0], currentIndexHTML = fs.readFileSync( path.join(__dirname, 'src', 'index.html'), { encoding: 'utf8' } ), $ = cheerio.load(currentIndexHTML); $('body').append(`<script src="build/${outputFileName}"></script>`); fs.writeFileSync( path.join(process.env.IONIC_WWW_DIR, 'index.html'), $.html() ); }); }
Я нашел лучшее решение этой проблемы из ветки ионного форума ( https://forum.ionicframework.com/t/file-revisions/75028/2, автор aszmyd), которая решает проблему хэширования имени файла main.css. также. Я сделал небольшие изменения в скрипте, так как у меня нет oauth.html или kajam.js.
Преимущество этого решения в том, что оно не пытается перехватить ионную сборку, а просто работает на результаты.
(Несомненно, кто-то найдет ошибку в том, как я публикую это, но это было очень полезно для меня, и я надеюсь, что для других. Я не могу представить себе наличие веб-приложения без полной очистки кэша для всех файлов css и js.)
Чтобы запустить это, просто добавьте:
node <the-file-name.js>
в вашей сборке, после завершения сборки ионного скрипта.
#!/usr/bin/env node
'use strict';
var md5File = require('md5-file'),
fs = require('fs');
/**
* This script renames files inside platforms/browser/www/ folder and updates their references in html files like index.html
* The mechanism is for improve caching. So file like `main.js` will be renamed to `main.[FILE-MD5-HASH].js` and its references
* in html files will be updated.
*/
var buildFolder = 'www/';
var assetsFolder = buildFolder + 'build/';
var jsFiles = [
'main'
];
var cssFiles = [
'main'
];
var htmlFilesToUpdate = [
'index.html'
];
var replacements = [];
jsFiles.forEach(function (file) {
var hash = md5File.sync(assetsFolder + file + '.js');
renameFile(file + '.js', file + '.' + hash + '.js');
});
cssFiles.forEach(function (file) {
var hash = md5File.sync(assetsFolder + file + '.css');
renameFile(file + '.css', file + '.' + hash + '.css');
});
htmlFilesToUpdate.forEach(function (htmlFile) {
console.log('Update "' + htmlFile + '" with new file revisions.');
console.log('Replacements: ' + JSON.stringify(replacements));
replacements.forEach(function (replacementObject) {
replaceInFile(buildFolder + htmlFile, replacementObject.from, replacementObject.to);
});
});
function renameFile(input, output) {
console.log('Rename "' + input + '" to "' + output + '"');
fs.rename(assetsFolder + input, assetsFolder + output);
if (fs.existsSync(assetsFolder + input + '.map')) {
console.log('Rename "' + input + '.map" to "' + output + '.map"');
fs.rename(assetsFolder + input + '.map', assetsFolder + output + '.map');
}
replacements.push({from: input, to: output});
}
function replaceInFile(file, regex, replacement) {
var fileContents = fs.readFileSync(file, 'utf-8');
fs.writeFileSync(file, fileContents.replace(regex, replacement), 'utf8');
}
Это решение отлично работает с Ionic 2.x & 3.x
#!/usr/bin/env node
var fs = require('fs'),
path = require('path'),
cheerio = require('cheerio'),
revHash = require('rev-hash');
/**
*
* @param string fileName
* @returns string
*/
function hashFile(file) {
// Get file name
var fileName = file.replace(/\.[^/.]+$/, "");
// Get file extension
var re = /(?:\.([^.]+))?$/;
var fileExtension = re.exec(file)[1];
var filePath = path.join(buildDir, file);
var fileHash = revHash(fs.readFileSync(filePath));
var fileNewName = `${fileName}.${fileHash}.${fileExtension}`;
var fileNewPath = path.join(buildDir, fileNewName);
var fileNewRelativePath = path.join('build', fileNewName);
//Rename file
console.log("cache-busting.js:hashFile:Renaming " + filePath + " to " + fileNewPath);
fs.renameSync(filePath, fileNewPath);
return fileNewRelativePath;
}
var rootDir = path.resolve(__dirname);
var wwwRootDir = path.resolve(rootDir, 'www');
var buildDir = path.join(wwwRootDir, 'build');
var indexPath = path.join(wwwRootDir, 'index.html');
$ = cheerio.load(fs.readFileSync(indexPath, 'utf-8'));
$('head link[href="build/main.css"]').attr('href', hashFile('main.css'));
$('body script[src="build/main.js"]').attr('src', hashFile('main.js'));
$('body script[src="build/polyfills.js"]').attr('src', hashFile('polyfills.js'));
$('body script[src="build/vendor.js"]').attr('src', hashFile('vendor.js'));
fs.writeFileSync(indexPath, $.html());