mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 19:45:25 +01: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:
		
							parent
							
								
									1640e9a490
								
							
						
					
					
						commit
						b8f1c9f048
					
				| @ -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; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user