Avatar ·

Как отобразить версию приложения из package.json в Angular (TypeScript)?

Всем привет! Я разрабатываю мобильное приложение на Angular + Ionic. Хочу отображать текущую версию приложения в футере или на странице "О программе". Обычно мы пишем версию вручную в `package.json`, и хотелось бы брать её оттуда, чтобы не дублировать. Пробовал сделать так: ```typescript import { version } from '../../package.json'; @Component({...}) export class AboutPage { appVersion = version; } ``` Но TypeScript ругается: "Cannot find module '../../package.json'. Consider using '--resolveJsonModule' to import module with '.json' extension". Потом я включил `resolveJsonModule` в `tsconfig.json`, но теперь при сборке вылетает ошибка, что `package.json` — это не модуль, и Webpack не может его зарезолвить. Пробовал читать через `fetch('/package.json')` — в рантайме файл недоступен. Есть ли нормальный способ получить версию из `package.json` в Angular-приложении? Чтобы работало и в dev-режиме, и в продакшене (сборка через `ng build --prod`). Желательно без костылей вроде копирования файла в assets. Заранее спасибо! Теги: angular, typescript, ionic-framework, version, package.json <<>>

Решение: использование Angular CLI environment или DefinePlugin

Проблема в том, что package.json — это не модуль, а конфигурационный файл Node.js. Импортировать его напрямую — плохая практика, особенно в продакшене. Лучший способ — внедрить версию на этапе сборки. Вот два надёжных подхода.

Способ 1: Через environment.ts (рекомендуется)

Создайте скрипт, который перед сборкой читает package.json и записывает версию в src/environments/version.ts.

Шаг 1. Установите пакет-помощник (если нужно):

npm install --save-dev fs-extra

Шаг 2. Создайте скрипт scripts/set-version.js:

const fs = require('fs-extra');
const path = require('path');

const packageJson = fs.readJsonSync(path.resolve(__dirname, '../package.json'));
const version = packageJson.version;

const content = `// Auto-generated. Do not edit.
export const appVersion = '${version}';
`;

fs.writeFileSync(path.resolve(__dirname, '../src/environments/version.ts'), content);
console.log(`Version set to: ${version}`);

Шаг 3. Добавьте скрипт в package.json:

"scripts": {
  "prebuild": "node scripts/set-version.js",
  "prestart": "node scripts/set-version.js",
  "build": "ng build",
  "start": "ng serve"
}

Шаг 4. Используйте в компоненте:

import { appVersion } from '../environments/version';

@Component({
  selector: 'app-footer',
  template: `<small>Версия: {{ version }}</small>`
})
export class FooterComponent {
  version = appVersion;
}

Перед каждой сборкой или запуском dev-сервера версия будет автоматически обновляться.

Способ 2: Через Webpack DefinePlugin (для продвинутых)

Если вы используете кастомную конфигурацию Webpack (например, через @angular-builders/custom-webpack), можно внедрить версию прямо в код:

// extra-webpack.config.js
const webpack = require('webpack');
const packageJson = require('./package.json');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'APP_VERSION': JSON.stringify(packageJson.version)
    })
  ]
};

В TypeScript объявите глобальную переменную:

// global.d.ts
declare const APP_VERSION: string;

Используйте:

version = APP_VERSION;

Почему это работает?

  • Версия подставляется на этапе сборки, а не в рантайме.
  • Не нужно импортировать package.json напрямую.
  • Работает и в dev, и в prod режиме.
  • Не требует копирования файлов в assets.

Первый способ проще и не требует дополнительных инструментов. Второй — чище, если вы уже используете кастомный Webpack.

<<>>

Альтернатива: использование Angular CLI и replace-in-file

Если не хотите создавать отдельный файл с версией, можно заменить плейсхолдер прямо в шаблоне или компоненте.

Шаг 1. Установите replace-in-file:

npm install --save-dev replace-in-file

Шаг 2. Создайте скрипт замены:

// scripts/replace-version.js
const replace = require('replace-in-file');
const packageJson = require('../package.json');

const options = {
  files: 'src/environments/environment.prod.ts',
  from: /APP_VERSION_PLACEHOLDER/g,
  to: packageJson.version,
};

replace(options).then(() => console.log('Version replaced!'));

Шаг 3. В environment.prod.ts напишите:

export const environment = {
  production: true,
  version: 'APP_VERSION_PLACEHOLDER'
};

Шаг 4. Добавьте скрипт в package.json:

"prebuild": "node scripts/replace-version.js"

Этот подход проще в настройке, но требует осторожности: если файл будет перезаписан (например, при обновлении Angular), плейсхолдер может остаться. Поэтому первый метод надёжнее.