Удаление атрибута 'data-testid' из тегов HTML. Webpack. Angular
Есть написанные тесты на Сepress, следуя документации Cypress лучшей практикой является ипользование кастомных атрибутов на HTML тегах таких как data-cy="something" либо data-testid="something". Но с точки зрения безопасноти, в продакшене не стоит использовать эти атрибуты. Было найдено решение в интернете по удалению аттрибутов из HTML во время сборки приложеня в продакшн. Но к сожаоению, оно не работает.
Имеется такая настройка в angular.json
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.extra.js",
"mergeStrategies": {
"externals": "append"
}
},
......
Вот непосредственно сам файл кастомного кофига WebPack, webpack.extra.js
let path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.html$/,
use: ['data-cy-loader'],
},
],
},
resolveLoader: {
alias: {
'data-cy-loader': path.join(__dirname, 'data-cy-loader.js'),
},
},
};
Ну и сам файл с функцией удаление атрибута по регулярному выражению - data-cy-loader.js
module.exports = (source) => {
var dataAttr = 'data-testid="([^"]*)"';
if (source.match(dataAttr)) {
source = source.replace(new RegExp(dataAttr, 'g'), '');
}
return source;
};
Методом логирования всё что я узнал, так это то что resolveLoader в webpack.extra.js не отрабатывет, то есть не запускает функцию. Ангуляр в принципе находит кастомных конфиг, но не использует конфигурацию в нём.
Ответы (1 шт):
Для подобного рода вопросов лучше давать больше информации, а именно:
- версия Angular
- какой компилятор шаблонов используется - Ivy или View Engine
Твой код не работает и не будет работать по той причине, что Angular не использует Webpack для предварительной обработки .html файлов.
В JITе компилятор использует трансформатор, который это:
templateUrl: './app.component.html'
заменяет на это:
template: __webpack_require__('raw-loader!./app.component.html')
и перед тем как код отправится в браузер, Webpack вызывает runLoaders(), который прогоняет контент .html файла через raw-loader, который в свою очередь превращает этот файл в псевдо-CommonJS модуль:
function rawLoader(source) {
return `module.exports = ${JSON.stringify(source)};`
}
Теоретически можно было бы заменить raw-loader через config.resolveLoader.alias['raw-loader'] = (путь к нашему файлу), и проделывать эти махинации с .html файлами, но как я сказал это работает только в JITе, т.е. с:
ng build --prod
это не прокатит.
Когда используется предварительная компиляция, то Angular:
- читает все
.tsфайлы - создает из каждого файла структуру данных
SourceFile - если
enableIvy = true- анализирует все компоненты через
ComponentDecoratorHandler
- анализирует все компоненты через
- если
enableIvy = false- анализирует компоненты через
DirectiveNormalizer
- анализирует компоненты через
при этом в этот же момент чтение .html файлов происходит напрямую через fs.readFileSync.
Внедриться в пайплайн компиляции невозможно в принципе, возможно пришлось бы патчить какие-то методы, но сам TS тебе этого не позволит, все узлы AST иммутабельные.
Что тебе мешает написать простой скрипт и запускать его на уровне CD, который будет проходиться по всем .html, .ts файлам и убирать эти атрибуты?
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const matches = glob.sync(path.join(__dirname, 'src/**/*.{ts,html}'));
for (const match of matches) {
fs.readFile(match, { encoding: 'utf-8' }, (error, source) => {
if (source.match(/data-testid=(['"])(.*)(['"])/) === null) {
return;
}
fs.writeFile(match, source.replace(/data-testid=(['"])(.*)(['"])/g, ''), () => {});
});
}