Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/5
This commit was merged in pull request #5.
This commit is contained in:
@@ -0,0 +1,396 @@
|
||||
# =============================================================
|
||||
# SPFx + Heft project bootstrap script (PowerShell)
|
||||
# Запустите из корня вашей ПУСТОЙ папки проекта:
|
||||
# .\setup-spfx-heft.ps1
|
||||
#
|
||||
# Если запуск скриптов заблокирован, выполните сначала:
|
||||
# Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
|
||||
# =============================================================
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Версия SPFx. Генератор ОБЯЗАН совпадать с версией пакетов ниже:
|
||||
# старый генератор создаёт проект на gulp + node-sass, который не собирается
|
||||
# на современных Node (node-gyp 3.8 требует Python 2).
|
||||
$SpfxVersion = "1.22.1"
|
||||
|
||||
# ---- Запись файлов ----
|
||||
# ВАЖНО: "Set-Content -Encoding UTF8" в Windows PowerShell 5.1 пишет UTF-8 С BOM.
|
||||
# Heft, tsc и node на BOM в .json/.js спотыкаются:
|
||||
# Unexpected token '<U+FEFF>', "<U+FEFF>{ ..." is not valid JSON
|
||||
# Поэтому все конфиги пишем строго UTF-8 без BOM.
|
||||
function Write-Utf8NoBom {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Content
|
||||
)
|
||||
$full = [System.IO.Path]::Combine((Get-Location).ProviderPath, $Path)
|
||||
$dir = [System.IO.Path]::GetDirectoryName($full)
|
||||
if ($dir -and -not (Test-Path $dir)) {
|
||||
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
||||
}
|
||||
[System.IO.File]::WriteAllText($full, ($Content -replace "`r?`n", "`r`n"), (New-Object System.Text.UTF8Encoding($false)))
|
||||
}
|
||||
|
||||
# ---- Цвета вывода ----
|
||||
function Info { param($msg) Write-Host "[INFO] $msg" -ForegroundColor Cyan }
|
||||
function Success { param($msg) Write-Host "[OK] $msg" -ForegroundColor Green }
|
||||
function Warn { param($msg) Write-Host "[WARN] $msg" -ForegroundColor Yellow }
|
||||
function Header { param($msg) Write-Host "`n$msg" -ForegroundColor White }
|
||||
|
||||
Header "================================================="
|
||||
Header " SPFx + Heft — автоматическая инициализация"
|
||||
Header "=================================================`n"
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 1. Проверка Node.js (SPFx 1.20+ требует Node 18+)
|
||||
# ---------------------------------------------------------
|
||||
Info "Проверка Node.js..."
|
||||
|
||||
try {
|
||||
$nodeVersion = (node --version).Trim()
|
||||
} catch {
|
||||
Warn "Node.js не найден. Установите Node 18 LTS: https://nodejs.org"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$nodeMajor = [int]($nodeVersion.TrimStart('v').Split('.')[0])
|
||||
# SPFx 1.22 объявляет engines: node >=22.14.0 <23.0.0 — на других мажорах
|
||||
# генератор и rig просто не установятся.
|
||||
if ($nodeMajor -ne 22) {
|
||||
Warn "Обнаружен Node.js $nodeVersion. SPFx $SpfxVersion требует Node 22.x (>=22.14.0 <23)."
|
||||
Warn "Переключитесь через nvm-windows: nvm install 22 && nvm use 22"
|
||||
exit 1
|
||||
}
|
||||
Success "Node.js $nodeVersion — подходит."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 1a. Папка должна быть пустой
|
||||
# ---------------------------------------------------------
|
||||
$leftovers = @("package.json", ".yo-rc.json", "node_modules", "gulpfile.js", "tslint.json") |
|
||||
Where-Object { Test-Path $_ }
|
||||
|
||||
if ($leftovers.Count -gt 0) {
|
||||
Warn "В текущей папке уже есть следы предыдущей генерации: $($leftovers -join ', ')"
|
||||
Warn "Скрипт рассчитан на ПУСТУЮ папку — иначе Yeoman смешает старый и новый проект."
|
||||
Warn "Уберите служебные файлы и запустите заново:"
|
||||
Warn " Remove-Item -Recurse -Force node_modules, config, package.json, package-lock.json, .yo-rc.json, gulpfile.js, tslint.json, tsconfig.json -ErrorAction SilentlyContinue"
|
||||
Warn "ВНИМАНИЕ: src\ и teams\ здесь НЕ перечислены намеренно — в src может лежать ваш код."
|
||||
Warn "Проверьте их содержимое вручную перед удалением."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 2. Вспомогательная функция: установка глобального пакета
|
||||
# ---------------------------------------------------------
|
||||
# Проверяем именно ПАКЕТ через "npm ls -g", а не наличие команды:
|
||||
# у @microsoft/generator-sharepoint своего бинарника нет, и проверка по "yo"
|
||||
# считала его установленным, оставляя старый генератор (1.11.0), который
|
||||
# генерирует проект на @microsoft/sp-build-web + node-sass → node-gyp 3 → python2.
|
||||
function Get-GlobalPackageVersion {
|
||||
param([string]$Package)
|
||||
|
||||
# Локально глушим Stop: "npm ls" отдаёт код 1 и пишет в stderr, когда пакета нет,
|
||||
# а в Windows PowerShell 5.1 stderr нативного exe при Stop роняет скрипт.
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
$json = npm ls -g $Package --depth=0 --json 2>$null | Out-String
|
||||
if ([string]::IsNullOrWhiteSpace($json)) { return $null }
|
||||
|
||||
try {
|
||||
$parsed = $json | ConvertFrom-Json
|
||||
} catch {
|
||||
return $null
|
||||
}
|
||||
|
||||
$dep = $parsed.dependencies.$Package
|
||||
if ($null -eq $dep -or [string]::IsNullOrWhiteSpace($dep.version)) { return $null }
|
||||
return $dep.version
|
||||
}
|
||||
|
||||
function Install-GlobalPackage {
|
||||
param(
|
||||
[string]$Package,
|
||||
[string]$Version = "" # пустая строка = любая установленная версия подходит
|
||||
)
|
||||
|
||||
$installed = Get-GlobalPackageVersion $Package
|
||||
|
||||
if ($Version -ne "") {
|
||||
if ($installed -eq $Version) {
|
||||
Success "$Package@$Version уже установлен."
|
||||
return
|
||||
}
|
||||
if ($installed) {
|
||||
Warn "$Package установлен версии $installed, требуется $Version — переустанавливаем."
|
||||
} else {
|
||||
Info "Устанавливаем $Package@$Version глобально..."
|
||||
}
|
||||
npm install -g "$Package@$Version"
|
||||
} else {
|
||||
if ($installed) {
|
||||
Success "$Package уже установлен (версия $installed)."
|
||||
return
|
||||
}
|
||||
Info "Устанавливаем $Package глобально..."
|
||||
npm install -g $Package
|
||||
}
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Warn "Не удалось установить $Package. Прерываем."
|
||||
exit 1
|
||||
}
|
||||
Success "$Package установлен."
|
||||
}
|
||||
|
||||
Install-GlobalPackage "yo"
|
||||
Install-GlobalPackage "@microsoft/generator-sharepoint" $SpfxVersion
|
||||
Install-GlobalPackage "@rushstack/heft"
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 3. Создание package.json
|
||||
# ---------------------------------------------------------
|
||||
Info "Создаём package.json..."
|
||||
|
||||
$packageJson = @'
|
||||
{
|
||||
"name": "spfx-heft-project",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "heft build",
|
||||
"bundle": "heft build && gulp bundle --ship",
|
||||
"package-solution": "heft build && gulp package-solution --ship",
|
||||
"serve": "heft build && gulp serve",
|
||||
"clean": "heft clean"
|
||||
},
|
||||
"overrides": {
|
||||
"ajv": "^8.0.0"
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom "package.json" $packageJson
|
||||
Success "package.json создан."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 4. Создание структуры папок
|
||||
# ---------------------------------------------------------
|
||||
Info "Создаём структуру папок..."
|
||||
New-Item -ItemType Directory -Force -Path "config" | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path "src\webparts" | Out-Null
|
||||
Success "Папки созданы."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 5. Запуск Yeoman-генератора SPFx
|
||||
# ---------------------------------------------------------
|
||||
Info "Запускаем Yeoman-генератор SPFx..."
|
||||
Write-Host ""
|
||||
Write-Host ">>> Сейчас откроется интерактивный генератор Yeoman." -ForegroundColor Yellow
|
||||
Write-Host ">>> Выберите тип: WebPart, Framework: No framework (или React)." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
# --skip-install: не даём генератору поставить свой gulp-стек до того,
|
||||
# как мы его выпилим. Иначе npm полезет собирать node-sass.
|
||||
yo "@microsoft/sharepoint" --skip-install
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Warn "Генератор Yeoman завершился с ошибкой. Прерываем."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Контроль: старый генератор мог протащить node-sass (нативная сборка,
|
||||
# node-gyp 3.8, требует Python 2 — на текущих Node не собирается вообще).
|
||||
if ((Test-Path "package.json") -and (Select-String -Path "package.json" -Pattern '"node-sass"' -Quiet)) {
|
||||
Warn "В package.json попал node-sass — значит, отработал устаревший генератор SPFx."
|
||||
Warn "Проверьте: npm ls -g @microsoft/generator-sharepoint (нужна $SpfxVersion)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Info "Убираем gulp-стек, оставшийся от генератора..."
|
||||
# Одним вызовом: каждый npm uninstall тянет за собой полный install остального.
|
||||
npm uninstall @microsoft/sp-build-web ajv gulp node-sass @microsoft/rush-stack-compiler-5.3
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 6. Установка Heft и Rush Stack зависимостей
|
||||
# ---------------------------------------------------------
|
||||
Info "Устанавливаем Heft и плагины..."
|
||||
|
||||
$devDeps = @(
|
||||
"@microsoft/spfx-web-build-rig@$SpfxVersion",
|
||||
"@microsoft/spfx-heft-plugins@$SpfxVersion",
|
||||
"@microsoft/eslint-config-spfx@$SpfxVersion",
|
||||
"@microsoft/eslint-plugin-spfx@$SpfxVersion",
|
||||
"@microsoft/sp-module-interfaces@$SpfxVersion",
|
||||
"@rushstack/eslint-config@4.5.2",
|
||||
"@rushstack/heft@1.1.2",
|
||||
"@types/heft-jest@1.0.2",
|
||||
"@typescript-eslint/parser@8.46.2"
|
||||
)
|
||||
|
||||
npm install --save-dev @($devDeps) --save-exact --force --legacy-peer-deps
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Warn "npm install завершился с ошибкой (код $LASTEXITCODE). Прерываем, чтобы не создавать конфиги поверх битого дерева."
|
||||
exit 1
|
||||
}
|
||||
|
||||
npm install typescript@~5.8.0 --save-dev
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Warn "Не удалось установить typescript. Прерываем."
|
||||
exit 1
|
||||
}
|
||||
|
||||
Success "Heft и плагины установлены."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 7. config/rig.json
|
||||
# ---------------------------------------------------------
|
||||
Info "Создаём config\rig.json..."
|
||||
New-Item -ItemType Directory -Force -Path "config" | Out-Null
|
||||
|
||||
$rigJson = @'
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@microsoft/spfx-web-build-rig"
|
||||
}
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom "config\rig.json" $rigJson
|
||||
Success "config\rig.json создан."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 8. config/sass.json
|
||||
# ---------------------------------------------------------
|
||||
Info "Создаём config\sass.json..."
|
||||
New-Item -ItemType Directory -Force -Path "config" | Out-Null
|
||||
|
||||
$sassJson = @'
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json",
|
||||
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/sass.json"
|
||||
}
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom "config\sass.json" $sassJson
|
||||
Success "config\sass.json создан."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 9. config/typescript.json
|
||||
# ---------------------------------------------------------
|
||||
Info "Создаём config\typescript.json..."
|
||||
New-Item -ItemType Directory -Force -Path "config" | Out-Null
|
||||
|
||||
$typescriptJson = @'
|
||||
{
|
||||
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/typescript.json",
|
||||
"staticAssetsToCopy": {
|
||||
"fileExtensions": [".resx", ".jpg", ".png", ".woff", ".eot", ".ttf", ".svg", ".gif"],
|
||||
"includeGlobs": ["webparts/*/loc/*.js"]
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom "config\typescript.json" $typescriptJson
|
||||
Success "config\typescript.json создан."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 8. tsconfig.json (если Yeoman ещё не создал)
|
||||
# ---------------------------------------------------------
|
||||
if (-not (Test-Path "tsconfig.json")) {
|
||||
Info "Создаём tsconfig.json..."
|
||||
|
||||
$tsConfig = @'
|
||||
{
|
||||
"extends": "./node_modules/@microsoft/spfx-web-build-rig/profiles/default/tsconfig-base.json"
|
||||
}
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom "tsconfig.json" $tsConfig
|
||||
Success "tsconfig.json создан."
|
||||
} else {
|
||||
Success "tsconfig.json уже существует, пропускаем."
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 9. .eslintrc.js (если не создан)
|
||||
# ---------------------------------------------------------
|
||||
if (-not (Test-Path ".eslintrc.js")) {
|
||||
Info "Создаём .eslintrc.js..."
|
||||
|
||||
$eslintConfig = @'
|
||||
require('@rushstack/eslint-config/patch/modern-module-resolution');
|
||||
|
||||
module.exports = {
|
||||
extends: ['@microsoft/eslint-config-spfx/lib/profiles/default'],
|
||||
parserOptions: { tsconfigRootDir: __dirname }
|
||||
};
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom ".eslintrc.js" $eslintConfig
|
||||
Success ".eslintrc.js создан."
|
||||
} else {
|
||||
Success ".eslintrc.js уже существует, пропускаем."
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 10. .gitignore
|
||||
# ---------------------------------------------------------
|
||||
Info "Создаём .gitignore..."
|
||||
|
||||
$gitignore = @'
|
||||
node_modules/
|
||||
lib/
|
||||
dist/
|
||||
temp/
|
||||
*.sppkg
|
||||
.heft/
|
||||
sharepoint/solution/
|
||||
'@
|
||||
|
||||
Write-Utf8NoBom ".gitignore" $gitignore
|
||||
Success ".gitignore создан."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 11. Финальный npm install
|
||||
# ---------------------------------------------------------
|
||||
$devDeps = @(
|
||||
"@microsoft/sp-component-base@$SpfxVersion",
|
||||
"@microsoft/sp-core-library@$SpfxVersion",
|
||||
"@microsoft/sp-lodash-subset@$SpfxVersion",
|
||||
"@microsoft/sp-office-ui-fabric-core@$SpfxVersion",
|
||||
"@microsoft/sp-property-pane@$SpfxVersion",
|
||||
"@microsoft/sp-webpart-base@$SpfxVersion"
|
||||
)
|
||||
|
||||
Info "Финальный npm install..."
|
||||
npm install @($devDeps) --save-exact --legacy-peer-deps
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Warn "Финальный npm install завершился с ошибкой (код $LASTEXITCODE)."
|
||||
exit 1
|
||||
}
|
||||
Success "Все зависимости установлены."
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Готово
|
||||
# ---------------------------------------------------------
|
||||
Write-Host ""
|
||||
Write-Host "=================================================" -ForegroundColor Green
|
||||
Write-Host " Проект успешно инициализирован!" -ForegroundColor Green
|
||||
Write-Host "=================================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host " Доступные команды:" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " npm run serve " -NoNewline -ForegroundColor Cyan
|
||||
Write-Host "— локальная разработка (gulp serve)"
|
||||
Write-Host " npm run build " -NoNewline -ForegroundColor Cyan
|
||||
Write-Host "— сборка через Heft"
|
||||
Write-Host " npm run bundle " -NoNewline -ForegroundColor Cyan
|
||||
Write-Host "— бандлинг для продакшна"
|
||||
Write-Host " npm run package-solution " -NoNewline -ForegroundColor Cyan
|
||||
Write-Host "— создание .sppkg пакета"
|
||||
Write-Host " npm run clean " -NoNewline -ForegroundColor Cyan
|
||||
Write-Host "— очистка артефактов сборки"
|
||||
Write-Host ""
|
||||
Write-Host " Следующий шаг: " -NoNewline -ForegroundColor Yellow
|
||||
Write-Host "npm run serve" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Reference in New Issue
Block a user