mirror of
https://github.com/go-gitea/gitea.git
synced 2025-09-10 16:43:10 +00:00
Migrate tools and configs to typescript, require node.js >= 22.18.0 (#35421)
Migrate all JS config and tools to TS and fix a number of type issues. This required Node.js 22.18.0 or greater where [type-stripping was enabled](https://nodejs.org/en/blog/release/v22.18.0) by default. Given that Node 22 is the current LTS, I think it's ok to assume that the user has a recent version of it. Webpack currently requires the `--disable-interpret` flag to work, should be fixed eventually with https://github.com/webpack/webpack-cli/issues/4525. `fast-glob` is replaced by `fs.globSync`, available in Node 22.0.0 or greater.
This commit is contained in:
@@ -18,6 +18,9 @@ RUN apk --no-cache add \
|
||||
&& npm install -g pnpm@10 \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# workaround for node >= 22.18.0 on alpine 3.22. Remove when upgrading to alpine 3.23
|
||||
COPY --from=docker.io/node:22-alpine3.22 /usr/local/bin/node /usr/local/bin/node
|
||||
|
||||
# Setup repo
|
||||
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
||||
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||
|
@@ -18,6 +18,9 @@ RUN apk --no-cache add \
|
||||
&& npm install -g pnpm@10 \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# workaround for node >= 22.18.0 on alpine 3.22. Remove when upgrading to alpine 3.23
|
||||
COPY --from=docker.io/node:22-alpine3.22 /usr/local/bin/node /usr/local/bin/node
|
||||
|
||||
# Setup repo
|
||||
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
||||
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||
|
16
Makefile
16
Makefile
@@ -127,7 +127,7 @@ GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/m
|
||||
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)
|
||||
|
||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
|
||||
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
|
||||
WEBPACK_CONFIGS := webpack.config.ts tailwind.config.ts
|
||||
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
|
||||
WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts
|
||||
|
||||
@@ -153,9 +153,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST)
|
||||
GO_DIRS := build cmd models modules routers services tests
|
||||
WEB_DIRS := web_src/js web_src/css
|
||||
|
||||
ESLINT_FILES := web_src/js tools *.js *.ts *.cjs tests/e2e
|
||||
ESLINT_FILES := web_src/js tools *.ts *.cjs tests/e2e
|
||||
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
|
||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
|
||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
|
||||
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
|
||||
|
||||
GO_SOURCES := $(wildcard *.go)
|
||||
@@ -407,7 +407,7 @@ lint-actions: ## lint action workflow files
|
||||
|
||||
.PHONY: lint-templates
|
||||
lint-templates: .venv node_modules ## lint template files
|
||||
@node tools/lint-templates-svg.js
|
||||
@node tools/lint-templates-svg.ts
|
||||
@uv run --frozen djlint $(shell find templates -type f -iname '*.tmpl')
|
||||
|
||||
.PHONY: lint-yaml
|
||||
@@ -421,7 +421,7 @@ watch: ## watch everything and continuously rebuild
|
||||
.PHONY: watch-frontend
|
||||
watch-frontend: node-check node_modules ## watch frontend files and continuously rebuild
|
||||
@rm -rf $(WEBPACK_DEST_ENTRIES)
|
||||
NODE_ENV=development pnpm exec webpack --watch --progress
|
||||
NODE_ENV=development pnpm exec webpack --watch --progress --disable-interpret
|
||||
|
||||
.PHONY: watch-backend
|
||||
watch-backend: go-check ## watch backend files and continuously rebuild
|
||||
@@ -877,13 +877,13 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) pnpm-lock.yaml
|
||||
@$(MAKE) -s node-check node_modules
|
||||
@rm -rf $(WEBPACK_DEST_ENTRIES)
|
||||
@echo "Running webpack..."
|
||||
@BROWSERSLIST_IGNORE_OLD_DATA=true pnpm exec webpack
|
||||
@BROWSERSLIST_IGNORE_OLD_DATA=true pnpm exec webpack --disable-interpret
|
||||
@touch $(WEBPACK_DEST)
|
||||
|
||||
.PHONY: svg
|
||||
svg: node-check | node_modules ## build svg files
|
||||
rm -rf $(SVG_DEST_DIR)
|
||||
node tools/generate-svg.js
|
||||
node tools/generate-svg.ts
|
||||
|
||||
.PHONY: svg-check
|
||||
svg-check: svg
|
||||
@@ -922,7 +922,7 @@ generate-gitignore: ## update gitignore files
|
||||
|
||||
.PHONY: generate-images
|
||||
generate-images: | node_modules ## generate images
|
||||
cd tools && node generate-images.js $(TAGS)
|
||||
cd tools && node generate-images.ts $(TAGS)
|
||||
|
||||
.PHONY: generate-manpage
|
||||
generate-manpage: ## generate manpage
|
||||
|
@@ -2,8 +2,8 @@
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.0.0",
|
||||
"engines": {
|
||||
"node": ">= 20.0.0",
|
||||
"pnpm": ">=10.0.0"
|
||||
"node": ">= 22.18.0",
|
||||
"pnpm": ">= 10.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@citation-js/core": "0.7.18",
|
||||
@@ -31,7 +31,6 @@
|
||||
"dropzone": "6.0.0-beta.2",
|
||||
"easymde": "2.20.0",
|
||||
"esbuild-loader": "4.3.0",
|
||||
"fast-glob": "3.3.3",
|
||||
"htmx.org": "2.0.6",
|
||||
"idiomorph": "0.7.3",
|
||||
"jquery": "3.7.1",
|
||||
@@ -110,7 +109,6 @@
|
||||
"stylelint-config-recommended": "17.0.0",
|
||||
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
|
||||
"stylelint-declaration-strict-value": "1.10.11",
|
||||
"stylelint-define-config": "16.22.0",
|
||||
"stylelint-value-no-unknown-custom-properties": "6.0.1",
|
||||
"svgo": "4.0.0",
|
||||
"type-fest": "4.41.0",
|
||||
|
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@@ -83,9 +83,6 @@ importers:
|
||||
esbuild-loader:
|
||||
specifier: 4.3.0
|
||||
version: 4.3.0(webpack@5.101.0)
|
||||
fast-glob:
|
||||
specifier: 3.3.3
|
||||
version: 3.3.3
|
||||
htmx.org:
|
||||
specifier: 2.0.6
|
||||
version: 2.0.6
|
||||
@@ -315,9 +312,6 @@ importers:
|
||||
stylelint-declaration-strict-value:
|
||||
specifier: 1.10.11
|
||||
version: 1.10.11(stylelint@16.23.1(typescript@5.8.3))
|
||||
stylelint-define-config:
|
||||
specifier: 16.22.0
|
||||
version: 16.22.0(stylelint@16.23.1(typescript@5.8.3))
|
||||
stylelint-value-no-unknown-custom-properties:
|
||||
specifier: 6.0.1
|
||||
version: 6.0.1(stylelint@16.23.1(typescript@5.8.3))
|
||||
@@ -4518,12 +4512,6 @@ packages:
|
||||
peerDependencies:
|
||||
stylelint: '>=7 <=16'
|
||||
|
||||
stylelint-define-config@16.22.0:
|
||||
resolution: {integrity: sha512-EEgHRugsryKo7LpenYyd4yLoZon3lHvRAi7WsMaZoRX9GPOkeDXrMga+N4VA4nK4Zus02EQwyYkndNQ64jaB2A==}
|
||||
engines: {node: '>=18.0.0', npm: '>=9.0.0', pnpm: '>=8.6.0'}
|
||||
peerDependencies:
|
||||
stylelint: '>=16.0.0'
|
||||
|
||||
stylelint-value-no-unknown-custom-properties@6.0.1:
|
||||
resolution: {integrity: sha512-N60PTdaTknB35j6D4FhW0GL2LlBRV++bRpXMMldWMQZ240yFQaoltzlLY4lXXs7Z0J5mNUYZQ/gjyVtU2DhCMA==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
@@ -9732,11 +9720,6 @@ snapshots:
|
||||
dependencies:
|
||||
stylelint: 16.23.1(typescript@5.8.3)
|
||||
|
||||
stylelint-define-config@16.22.0(stylelint@16.23.1(typescript@5.8.3)):
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
stylelint: 16.23.1(typescript@5.8.3)
|
||||
|
||||
stylelint-value-no-unknown-custom-properties@6.0.1(stylelint@16.23.1(typescript@5.8.3)):
|
||||
dependencies:
|
||||
postcss-value-parser: 4.2.0
|
||||
|
@@ -1,6 +1,5 @@
|
||||
// @ts-check
|
||||
import {defineConfig} from 'stylelint-define-config';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import type {Config} from 'stylelint';
|
||||
|
||||
const cssVarFiles = [
|
||||
fileURLToPath(new URL('web_src/css/base.css', import.meta.url)),
|
||||
@@ -8,7 +7,7 @@ const cssVarFiles = [
|
||||
fileURLToPath(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url)),
|
||||
];
|
||||
|
||||
export default defineConfig({
|
||||
export default {
|
||||
extends: 'stylelint-config-recommended',
|
||||
reportUnscopedDisables: true,
|
||||
reportNeedlessDisables: true,
|
||||
@@ -124,7 +123,6 @@ export default defineConfig({
|
||||
'csstools/value-no-unknown-custom-properties': [true, {importFrom: cssVarFiles}],
|
||||
'declaration-block-no-duplicate-properties': [true, {ignore: ['consecutive-duplicates-with-different-values']}],
|
||||
'declaration-block-no-redundant-longhand-properties': [true, {ignoreShorthands: ['flex-flow', 'overflow', 'grid-template']}],
|
||||
// @ts-expect-error - https://github.com/stylelint-types/stylelint-define-config/issues/1
|
||||
'declaration-property-unit-disallowed-list': {'line-height': ['em']},
|
||||
'declaration-property-value-disallowed-list': {'word-break': ['break-word']},
|
||||
'font-family-name-quotes': 'always-where-recommended',
|
||||
@@ -148,4 +146,4 @@ export default defineConfig({
|
||||
'shorthand-property-no-redundant-values': true,
|
||||
'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}],
|
||||
},
|
||||
});
|
||||
} satisfies Config;
|
@@ -2,17 +2,18 @@ import {readFileSync} from 'node:fs';
|
||||
import {env} from 'node:process';
|
||||
import {parse} from 'postcss';
|
||||
import plugin from 'tailwindcss/plugin.js';
|
||||
import type {Config} from 'tailwindcss';
|
||||
|
||||
const isProduction = env.NODE_ENV !== 'development';
|
||||
|
||||
function extractRootVars(css) {
|
||||
function extractRootVars(css: string) {
|
||||
const root = parse(css);
|
||||
const vars = new Set();
|
||||
const vars = new Set<string>();
|
||||
root.walkRules((rule) => {
|
||||
if (rule.selector !== ':root') return;
|
||||
rule.each((decl) => {
|
||||
if (decl.value && decl.prop.startsWith('--')) {
|
||||
vars.add(decl.prop.substring(2));
|
||||
rule.each((node) => {
|
||||
if (node.type === 'decl' && node.value && node.prop.startsWith('--')) {
|
||||
vars.add(node.prop.substring(2));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -120,4 +121,4 @@ export default {
|
||||
});
|
||||
}),
|
||||
],
|
||||
};
|
||||
} satisfies Config;
|
@@ -4,12 +4,7 @@ import {optimize} from 'svgo';
|
||||
import {readFile, writeFile} from 'node:fs/promises';
|
||||
import {argv, exit} from 'node:process';
|
||||
|
||||
function doExit(err) {
|
||||
if (err) console.error(err);
|
||||
exit(err ? 1 : 0);
|
||||
}
|
||||
|
||||
async function generate(svg, path, {size, bg}) {
|
||||
async function generate(svg: string, path: string, {size, bg}: {size: number, bg?: boolean}) {
|
||||
const outputFile = new URL(path, import.meta.url);
|
||||
|
||||
if (String(outputFile).endsWith('.svg')) {
|
||||
@@ -19,7 +14,9 @@ async function generate(svg, path, {size, bg}) {
|
||||
'removeDimensions',
|
||||
{
|
||||
name: 'addAttributesToSVGElement',
|
||||
params: {attributes: [{width: size}, {height: size}]},
|
||||
params: {
|
||||
attributes: [{width: String(size)}, {height: String(size)}],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -57,7 +54,8 @@ async function main() {
|
||||
}
|
||||
|
||||
try {
|
||||
doExit(await main());
|
||||
await main();
|
||||
} catch (err) {
|
||||
doExit(err);
|
||||
console.error(err);
|
||||
exit(1);
|
||||
}
|
@@ -1,27 +1,29 @@
|
||||
#!/usr/bin/env node
|
||||
import fastGlob from 'fast-glob';
|
||||
import {optimize} from 'svgo';
|
||||
import {parse} from 'node:path';
|
||||
import {dirname, parse} from 'node:path';
|
||||
import {globSync, writeFileSync} from 'node:fs';
|
||||
import {readFile, writeFile, mkdir} from 'node:fs/promises';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import {exit} from 'node:process';
|
||||
import * as fs from 'node:fs';
|
||||
import type {Manifest} from 'material-icon-theme';
|
||||
|
||||
const glob = (pattern) => fastGlob.sync(pattern, {
|
||||
cwd: fileURLToPath(new URL('..', import.meta.url)),
|
||||
absolute: true,
|
||||
});
|
||||
const glob = (pattern: string) => globSync(pattern, {cwd: dirname(import.meta.dirname)});
|
||||
|
||||
async function processAssetsSvgFile(file, {prefix, fullName} = {}) {
|
||||
type Opts = {
|
||||
prefix?: string,
|
||||
fullName?: string,
|
||||
};
|
||||
|
||||
async function processAssetsSvgFile(path: string, {prefix, fullName}: Opts = {}) {
|
||||
let name = fullName;
|
||||
if (!name) {
|
||||
name = parse(file).name;
|
||||
name = parse(path).name;
|
||||
if (prefix) name = `${prefix}-${name}`;
|
||||
if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
|
||||
}
|
||||
// Set the `xmlns` attribute so that the files are displayable in standalone documents
|
||||
// The svg backend module will strip the attribute during startup for inline display
|
||||
const {data} = optimize(await readFile(file, 'utf8'), {
|
||||
const {data} = optimize(await readFile(path, 'utf8'), {
|
||||
plugins: [
|
||||
{name: 'preset-default'},
|
||||
{name: 'removeDimensions'},
|
||||
@@ -41,16 +43,16 @@ async function processAssetsSvgFile(file, {prefix, fullName} = {}) {
|
||||
await writeFile(fileURLToPath(new URL(`../public/assets/img/svg/${name}.svg`, import.meta.url)), data);
|
||||
}
|
||||
|
||||
function processAssetsSvgFiles(pattern, opts) {
|
||||
return glob(pattern).map((file) => processAssetsSvgFile(file, opts));
|
||||
function processAssetsSvgFiles(pattern: string, opts: Opts = {}) {
|
||||
return glob(pattern).map((path) => processAssetsSvgFile(path, opts));
|
||||
}
|
||||
|
||||
async function processMaterialFileIcons() {
|
||||
const files = glob('node_modules/material-icon-theme/icons/*.svg');
|
||||
const svgSymbols = {};
|
||||
for (const file of files) {
|
||||
const paths = glob('node_modules/material-icon-theme/icons/*.svg');
|
||||
const svgSymbols: Record<string, string> = {};
|
||||
for (const path of paths) {
|
||||
// remove all unnecessary attributes, only keep "viewBox"
|
||||
const {data} = optimize(await readFile(file, 'utf8'), {
|
||||
const {data} = optimize(await readFile(path, 'utf8'), {
|
||||
plugins: [
|
||||
{name: 'preset-default'},
|
||||
{name: 'removeDimensions'},
|
||||
@@ -58,16 +60,16 @@ async function processMaterialFileIcons() {
|
||||
{name: 'removeAttrs', params: {attrs: 'xml:space', elemSeparator: ','}},
|
||||
],
|
||||
});
|
||||
const svgName = parse(file).name;
|
||||
const svgName = parse(path).name;
|
||||
// intentionally use single quote here to avoid escaping
|
||||
svgSymbols[svgName] = data.replace(/"/g, `'`);
|
||||
}
|
||||
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
|
||||
writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
|
||||
|
||||
const vscodeExtensionsJson = await readFile(fileURLToPath(new URL(`generate-svg-vscode-extensions.json`, import.meta.url)));
|
||||
const vscodeExtensions = JSON.parse(vscodeExtensionsJson);
|
||||
const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)));
|
||||
const iconRules = JSON.parse(iconRulesJson);
|
||||
const vscodeExtensionsJson = await readFile(fileURLToPath(new URL(`generate-svg-vscode-extensions.json`, import.meta.url)), 'utf8');
|
||||
const vscodeExtensions = JSON.parse(vscodeExtensionsJson) as Record<string, string>;
|
||||
const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)), 'utf8');
|
||||
const iconRules = JSON.parse(iconRulesJson) as Manifest;
|
||||
// The rules are from VSCode material-icon-theme, we need to adjust them to our needs
|
||||
// 1. We only use lowercase filenames to match (it should be good enough for most cases and more efficient)
|
||||
// 2. We do not have a "Language ID" system:
|
||||
@@ -91,7 +93,7 @@ async function processMaterialFileIcons() {
|
||||
}
|
||||
}
|
||||
const iconRulesPretty = JSON.stringify(iconRules, null, 2);
|
||||
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
|
||||
writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
|
||||
}
|
||||
|
||||
async function main() {
|
@@ -1,11 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
import {readdirSync, readFileSync} from 'node:fs';
|
||||
import {readdirSync, readFileSync, globSync} from 'node:fs';
|
||||
import {parse, relative} from 'node:path';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import {exit} from 'node:process';
|
||||
import fastGlob from 'fast-glob';
|
||||
|
||||
const knownSvgs = new Set();
|
||||
const knownSvgs = new Set<string>();
|
||||
for (const file of readdirSync(new URL('../public/assets/img/svg', import.meta.url))) {
|
||||
knownSvgs.add(parse(file).name);
|
||||
}
|
||||
@@ -13,7 +12,7 @@ for (const file of readdirSync(new URL('../public/assets/img/svg', import.meta.u
|
||||
const rootPath = fileURLToPath(new URL('..', import.meta.url));
|
||||
let hadErrors = false;
|
||||
|
||||
for (const file of fastGlob.sync(fileURLToPath(new URL('../templates/**/*.tmpl', import.meta.url)))) {
|
||||
for (const file of globSync(fileURLToPath(new URL('../templates/**/*.tmpl', import.meta.url)))) {
|
||||
const content = readFileSync(file, 'utf8');
|
||||
for (const [_, name] of content.matchAll(/svg ["'`]([^"'`]+)["'`]/g)) {
|
||||
if (!knownSvgs.has(name)) {
|
@@ -41,6 +41,7 @@
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"./web_src/js/globals.d.ts",
|
||||
"./types.d.ts",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
9
types.d.ts
vendored
Normal file
9
types.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
declare module 'add-asset-webpack-plugin' {
|
||||
const plugin: any;
|
||||
export = plugin
|
||||
}
|
||||
|
||||
declare module '@techknowlogick/license-checker-webpack-plugin' {
|
||||
const plugin: any;
|
||||
export = plugin
|
||||
}
|
@@ -1,3 +1,5 @@
|
||||
import type {Config} from 'updates';
|
||||
|
||||
export default {
|
||||
exclude: [
|
||||
'@mcaptcha/vanilla-glue', // breaking changes in rc versions need to be handled
|
||||
@@ -11,4 +13,4 @@ export default {
|
||||
'eslint-plugin-vitest', // need to migrate to eslint flat config first
|
||||
'tailwindcss', // need to migrate
|
||||
],
|
||||
};
|
||||
} satisfies Config;
|
@@ -1,4 +1,3 @@
|
||||
import fastGlob from 'fast-glob';
|
||||
import wrapAnsi from 'wrap-ansi';
|
||||
import AddAssetPlugin from 'add-asset-webpack-plugin';
|
||||
import LicenseCheckerWebpackPlugin from '@techknowlogick/license-checker-webpack-plugin';
|
||||
@@ -6,28 +5,23 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
|
||||
import {VueLoaderPlugin} from 'vue-loader';
|
||||
import EsBuildLoader from 'esbuild-loader';
|
||||
import {parse, dirname} from 'node:path';
|
||||
import webpack from 'webpack';
|
||||
import {parse} from 'node:path';
|
||||
import webpack, {type Configuration, type EntryObject} from 'webpack';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import {readFileSync} from 'node:fs';
|
||||
import {readFileSync, globSync} from 'node:fs';
|
||||
import {env} from 'node:process';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
import tailwindConfig from './tailwind.config.js';
|
||||
import tailwindConfig from './tailwind.config.ts';
|
||||
import tailwindcssNesting from 'tailwindcss/nesting/index.js';
|
||||
import postcssNesting from 'postcss-nesting';
|
||||
|
||||
const {EsbuildPlugin} = EsBuildLoader;
|
||||
const {SourceMapDevToolPlugin, DefinePlugin, EnvironmentPlugin} = webpack;
|
||||
const formatLicenseText = (licenseText) => wrapAnsi(licenseText || '', 80).trim();
|
||||
const formatLicenseText = (licenseText: string) => wrapAnsi(licenseText || '', 80).trim();
|
||||
|
||||
const glob = (pattern) => fastGlob.sync(pattern, {
|
||||
cwd: dirname(fileURLToPath(new URL(import.meta.url))),
|
||||
absolute: true,
|
||||
});
|
||||
|
||||
const themes = {};
|
||||
for (const path of glob('web_src/css/themes/*.css')) {
|
||||
themes[parse(path).name] = [path];
|
||||
const themes: EntryObject = {};
|
||||
for (const path of globSync('web_src/css/themes/*.css', {cwd: import.meta.dirname})) {
|
||||
themes[parse(path).name] = [`./${path}`];
|
||||
}
|
||||
|
||||
const isProduction = env.NODE_ENV !== 'development';
|
||||
@@ -55,12 +49,12 @@ const webComponents = new Set([
|
||||
'text-expander',
|
||||
]);
|
||||
|
||||
const filterCssImport = (url, ...args) => {
|
||||
const filterCssImport = (url: string, ...args: Array<any>) => {
|
||||
const cssFile = args[1] || args[0]; // resourcePath is 2nd argument for url and 3rd for import
|
||||
const importedFile = url.replace(/[?#].+/, '').toLowerCase();
|
||||
|
||||
if (cssFile.includes('fomantic')) {
|
||||
if (/brand-icons/.test(importedFile)) return false;
|
||||
if (importedFile.includes('brand-icons')) return false;
|
||||
if (/(eot|ttf|otf|woff|svg)$/i.test(importedFile)) return false;
|
||||
}
|
||||
|
||||
@@ -71,7 +65,6 @@ const filterCssImport = (url, ...args) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
/** @type {import("webpack").Configuration} */
|
||||
export default {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
entry: {
|
||||
@@ -100,7 +93,7 @@ export default {
|
||||
path: fileURLToPath(new URL('public/assets', import.meta.url)),
|
||||
filename: () => 'js/[name].js',
|
||||
chunkFilename: ({chunk}) => {
|
||||
const language = (/monaco.*languages?_.+?_(.+?)_/.exec(chunk.id) || [])[1];
|
||||
const language = (/monaco.*languages?_.+?_(.+?)_/.exec(String(chunk.id)) || [])[1];
|
||||
return `js/${language ? `monaco-language-${language.toLowerCase()}` : `[name]`}.[contenthash:8].js`;
|
||||
},
|
||||
},
|
||||
@@ -129,7 +122,7 @@ export default {
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
isCustomElement: (tag) => webComponents.has(tag),
|
||||
isCustomElement: (tag: string) => webComponents.has(tag),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -225,10 +218,10 @@ export default {
|
||||
}),
|
||||
isProduction ? new LicenseCheckerWebpackPlugin({
|
||||
outputFilename: 'licenses.txt',
|
||||
outputWriter: ({dependencies}) => {
|
||||
outputWriter: ({dependencies}: {dependencies: Array<Record<string, string>>}) => {
|
||||
const line = '-'.repeat(80);
|
||||
const goJson = readFileSync('assets/go-licenses.json', 'utf8');
|
||||
const goModules = JSON.parse(goJson).map(({name, licenseText}) => {
|
||||
const goModules = JSON.parse(goJson).map(({name, licenseText}: Record<string, string>) => {
|
||||
return {name, body: formatLicenseText(licenseText)};
|
||||
});
|
||||
const jsModules = dependencies.map(({name, version, licenseName, licenseText}) => {
|
||||
@@ -285,4 +278,4 @@ export default {
|
||||
reasons: false,
|
||||
runtimeModules: false,
|
||||
},
|
||||
};
|
||||
} satisfies Configuration;
|
Reference in New Issue
Block a user