* begin vite stuff (does not work yet)

* finalize vite switch + cleanup package.json

* Assets path, re-add async, fix z

* Remove source-map-support

---------

Co-authored-by: Liam <byteslice@airmail.cc>
This commit is contained in:
Nighty 2024-04-30 02:39:52 +02:00 committed by GitHub
parent 77548057e8
commit 42cd107b2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 1451 additions and 4063 deletions

View file

@ -1,3 +1,3 @@
js/vendor/* js/vendor/*
webpack.config.js vite.config.ts
jest.config.js jest.config.js

View file

@ -9,13 +9,13 @@
@import "global"; @import "global";
// Because FA is a SPECIAL SNOWFLAKE. // Because FA is a SPECIAL SNOWFLAKE.
$fa-font-path: '~@fortawesome/fontawesome-free/webfonts'; $fa-font-path: '@fortawesome/fontawesome-free/webfonts';
@import "~@fortawesome/fontawesome-free/scss/fontawesome.scss"; @import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
@import "~@fortawesome/fontawesome-free/scss/solid.scss"; @import "@fortawesome/fontawesome-free/scss/solid.scss";
@import "~@fortawesome/fontawesome-free/scss/regular.scss"; @import "@fortawesome/fontawesome-free/scss/regular.scss";
@import "~@fortawesome/fontawesome-free/scss/brands.scss"; @import "@fortawesome/fontawesome-free/scss/brands.scss";
@import "~normalize-scss/sass/normalize/import-now"; @import "normalize-scss/sass/normalize/import-now";
body { body {
background-color: $background_color; background-color: $background_color;
@ -469,26 +469,26 @@ span.stat {
@import "shame"; @import "shame";
@import "text"; @import "text";
@import "~views/adverts"; @import "views/adverts";
@import "~views/approval"; @import "views/approval";
@import "~views/badges"; @import "views/badges";
@import "~views/channels"; @import "views/channels";
@import "~views/comments"; @import "views/comments";
@import "~views/commissions"; @import "views/commissions";
@import "~views/communications"; @import "views/communications";
@import "~views/duplicate_reports"; @import "views/duplicate_reports";
@import "~views/filters"; @import "views/filters";
@import "~views/galleries"; @import "views/galleries";
@import "~views/images"; @import "views/images";
@import "~views/pages"; @import "views/pages";
@import "~views/polls"; @import "views/polls";
@import "~views/posts"; @import "views/posts";
@import "~views/profiles"; @import "views/profiles";
@import "~views/pagination"; @import "views/pagination";
@import "~views/search"; @import "views/search";
@import "~views/staff"; @import "views/staff";
@import "~views/stats"; @import "views/stats";
@import "~views/tags"; @import "views/tags";
.no-overflow { .no-overflow {
overflow: hidden; overflow: hidden;

View file

@ -190,4 +190,4 @@ $dnp_warning_hover_color: lighten($vote_down_color, 10%);
$poll_form_label_background: lighten($border_color, 8); $poll_form_label_background: lighten($border_color, 8);
$tag_dropdown_hover_background: darken($meta_color, 4%); $tag_dropdown_hover_background: darken($meta_color, 4%);
@import "~common/base"; @import "common/base";

View file

@ -180,4 +180,4 @@ $dnp_warning_hover_color: lighten($vote_down_color, 10%);
$poll_form_label_background: lighten($border_color, 8); $poll_form_label_background: lighten($border_color, 8);
$tag_dropdown_hover_background: darken($meta_color, 4%); $tag_dropdown_hover_background: darken($meta_color, 4%);
@import "~common/base"; @import "common/base";

View file

@ -192,4 +192,4 @@ $dnp_warning_hover_color: lighten($vote_down_color, 10%);
$poll_form_label_background: lighten($border_color, 8); $poll_form_label_background: lighten($border_color, 8);
$tag_dropdown_hover_background: darken($meta_color, 4%); $tag_dropdown_hover_background: darken($meta_color, 4%);
@import "~common/base"; @import "common/base";

View file

@ -2,8 +2,8 @@
* Autocomplete. * Autocomplete.
*/ */
import { LocalAutocompleter } from 'utils/local-autocompleter'; import { LocalAutocompleter } from './utils/local-autocompleter';
import { handleError } from 'utils/requests'; import { handleError } from './utils/requests';
const cache = {}; const cache = {};
let inputField, originalTerm; let inputField, originalTerm;

View file

@ -57,8 +57,8 @@ export function makeEl<Tag extends keyof HTMLElementTagNameMap>(tag: Tag, attr?:
if (attr) { if (attr) {
for (const prop in attr) { for (const prop in attr) {
const newValue = attr[prop]; const newValue = attr[prop];
if (typeof newValue !== 'undefined') { if (newValue) {
el[prop] = newValue as Exclude<typeof newValue, undefined>; el[prop] = newValue;
} }
} }
} }

5103
assets/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,60 +1,37 @@
{ {
"type": "module", "type": "module",
"scripts": { "scripts": {
"deploy": "cross-env NODE_ENV=production webpack", "deploy": "cross-env NODE_ENV=production tsc && cross-env NODE_ENV=production vite build",
"lint": "eslint . --ext .js,.ts", "lint": "eslint . --ext .js,.ts",
"test": "jest --ci", "test": "jest --ci",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"watch": "webpack --watch" "dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.3.0", "@fortawesome/fontawesome-free": "^6.5.2",
"@rollup/plugin-multi-entry": "^6.0.0", "@types/web": "^0.0.143",
"@rollup/plugin-typescript": "^11.0.0", "@typescript-eslint/eslint-plugin": "^7.8.0",
"@rollup/plugin-virtual": "^3.0.1", "@typescript-eslint/parser": "^7.8.0",
"@types/web": "^0.0.91", "autoprefixer": "^10.4.19",
"@typescript-eslint/eslint-plugin": "^5.52.0",
"@typescript-eslint/parser": "^5.52.0",
"acorn": "^8.8.2",
"autoprefixer": "^10.4.13",
"brunch": "^4.0.2",
"copy-webpack-plugin": "^11.0.0",
"copycat-brunch": "^1.1.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^5.0.0",
"eslint": "^8.34.0", "eslint": "^8.34.0",
"eslint-webpack-plugin": "^4.0.0", "jest-environment-jsdom": "^29.7.0",
"file-loader": "^6.2.0", "normalize-scss": "^8.0.0",
"ignore-emit-webpack-plugin": "^2.0.6", "sass": "^1.75.0",
"jest-environment-jsdom": "^29.4.3", "tslib": "^2.6.2",
"mini-css-extract-plugin": "^2.7.2", "typescript": "^5.4",
"normalize-scss": "^7.0.1", "vite": "^5.2"
"postcss": "^8.4.31",
"postcss-loader": "^7.2.4",
"postcss-scss": "^4.0.6",
"postcss-url": "^10.1.3",
"rollup": "^2.57.0",
"rollup-plugin-includepaths": "^0.2.4",
"sass": "^1.58.3",
"sass-loader": "^13.2.0",
"source-map-support": "^0.5.21",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.6",
"tslib": "^2.5.0",
"typescript": "^4.9",
"webpack": "^5.76.0",
"webpack-cli": "^5.0.1",
"webpack-rollup-loader": "^0.8.1"
}, },
"devDependencies": { "devDependencies": {
"@testing-library/dom": "^9.0.0", "@testing-library/dom": "^10.1.0",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^6.4.2",
"@types/jest": "^29.4.0", "@types/jest": "^29.5.12",
"eslint-plugin-jest": "^27.2.1", "eslint-plugin-jest": "^28.3.0",
"eslint-plugin-jest-dom": "^4.0.3", "eslint-plugin-jest-dom": "^5.4.0",
"jest": "^29.4.3", "jest": "^29.7.0",
"jest-fetch-mock": "^3.0.3", "jest-fetch-mock": "^3.0.3",
"ts-jest": "^29.1.0" "ts-jest": "^29.1.2"
} }
} }

View file

@ -1,16 +1,24 @@
{ {
"compilerOptions": { "compilerOptions": {
"noEmit": true,
"baseUrl": "./js", "baseUrl": "./js",
"target": "ES2018", "target": "ES2020",
"useDefineForClassFields": true,
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "Node",
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"lib": [ "lib": [
"ES2018", "ES2020",
"DOM" "DOM",
"DOM.Iterable"
], ],
"moduleResolution": "Node",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"strict": true "strict": true
} }
} }

66
assets/vite.config.ts Normal file
View file

@ -0,0 +1,66 @@
import fs from 'fs';
import path from 'path';
import autoprefixer from 'autoprefixer';
import { defineConfig, UserConfig, ConfigEnv } from 'vite';
export default defineConfig(({ command }: ConfigEnv): UserConfig => {
const isDev = command !== 'build';
if (isDev) {
process.stdin.on('close', () => {
// eslint-disable-next-line no-process-exit
process.exit(0);
});
process.stdin.resume();
}
const themeNames =
fs.readdirSync(path.resolve(__dirname, 'css/themes/')).map(name => {
const m = name.match(/([-a-z]+).scss/);
if (m) { return m[1]; }
return null;
});
const themes = new Map();
for (const name of themeNames) {
themes.set(`css/${name}`, `./css/themes/${name}.scss`);
}
return {
publicDir: 'static',
plugins: [],
resolve: {
alias: {
common: path.resolve(__dirname, 'css/common/'),
views: path.resolve(__dirname, 'css/views/')
}
},
build: {
target: 'es2020',
outDir: path.resolve(__dirname, '../priv/static'),
emptyOutDir: false,
sourcemap: isDev,
manifest: false,
cssCodeSplit: true,
rollupOptions: {
input: {
'js/app': './js/app.js',
...Object.fromEntries(themes)
},
output: {
entryFileNames: '[name].js',
chunkFileNames: '[name].js',
assetFileNames: '[name][extname]'
}
}
},
css: {
postcss: {
plugins: [autoprefixer]
}
}
};
});

View file

@ -1,156 +0,0 @@
import fs from 'fs';
import path from 'path';
import url from 'url';
import TerserPlugin from 'terser-webpack-plugin';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import CopyPlugin from 'copy-webpack-plugin';
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import IgnoreEmitPlugin from 'ignore-emit-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import autoprefixer from 'autoprefixer';
import rollupPluginIncludepaths from 'rollup-plugin-includepaths';
import rollupPluginMultiEntry from '@rollup/plugin-multi-entry';
import rollupPluginTypescript from '@rollup/plugin-typescript';
const isDevelopment = process.env.NODE_ENV !== 'production';
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
const includePaths = rollupPluginIncludepaths();
const multiEntry = rollupPluginMultiEntry();
const typescript = rollupPluginTypescript();
let plugins = [
new IgnoreEmitPlugin(/css\/.*(?<!css)$/),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
new CopyPlugin({
patterns: [
{ from: path.resolve(__dirname, 'static') },
],
}),
];
if (isDevelopment) {
plugins = plugins.concat([
new ESLintPlugin({
extensions: ['js', 'ts'],
failOnError: true,
failOnWarning: isDevelopment
})
]);
}
else {
plugins = plugins.concat([
new TerserPlugin({
parallel: true,
}),
new CssMinimizerPlugin(),
]);
}
const themeNames =
fs.readdirSync(path.resolve(__dirname, 'css/themes')).map(name =>
name.match(/([-a-z]+).scss/)[1]
);
const themes = {};
for (const name of themeNames) {
themes[`css/${name}`] = `./css/themes/${name}.scss`;
}
export default {
mode: isDevelopment ? 'development' : 'production',
entry: {
'js/app.js': './js/app.js',
...themes
},
output: {
filename: '[name]',
path: path.resolve(__dirname, '../priv/static'),
},
optimization: {
minimize: !isDevelopment,
providedExports: true,
usedExports: true,
concatenateModules: true,
},
devtool: isDevelopment ? 'inline-source-map' : undefined,
performance: { hints: false },
resolve: {
alias: {
common: path.resolve(__dirname, 'css/common/'),
views: path.resolve(__dirname, 'css/views/')
}
},
module: {
rules: [
{
test: /\.(ttf|eot|svg|woff2?)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: './fonts',
publicPath: '../fonts',
},
dependency: { not: ['url'] },
},
{
test: /app\.js/,
use: [
{
loader: 'webpack-rollup-loader',
options: {
plugins: [
includePaths,
multiEntry,
typescript,
]
}
},
],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: isDevelopment,
url: {
filter: (url, _resourcePath) => {
return !url.startsWith('/');
}
}
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
sourceMaps: isDevelopment,
ident: 'postcss',
syntax: 'postcss-scss',
plugins: [
autoprefixer(),
],
},
},
},
{
loader: 'sass-loader',
options: {
sourceMap: isDevelopment,
sassOptions: {
quietDeps: true
}
}
},
]
},
],
},
plugins,
};

View file

@ -8,7 +8,7 @@ config :philomena, Philomena.Repo, show_sensitive_data_on_connection_error: true
# #
# The watchers configuration can be used to run external # The watchers configuration can be used to run external
# watchers to your application. For example, we use it # watchers to your application. For example, we use it
# with webpack to recompile .js and .css sources. # with vite to recompile .js and .css sources.
config :philomena, PhilomenaWeb.Endpoint, config :philomena, PhilomenaWeb.Endpoint,
http: [port: 4000], http: [port: 4000],
debug_errors: true, debug_errors: true,
@ -16,11 +16,13 @@ config :philomena, PhilomenaWeb.Endpoint,
check_origin: false, check_origin: false,
watchers: [ watchers: [
node: [ node: [
"node_modules/webpack/bin/webpack.js", "node_modules/vite/bin/vite.js",
"build",
"--mode", "--mode",
"development", "development",
"--watch", "--watch",
"--watch-options-stdin", "--config",
"vite.config.ts",
cd: Path.expand("../assets", __DIR__) cd: Path.expand("../assets", __DIR__)
] ]
] ]

View file

@ -19,7 +19,7 @@ html lang="en"
meta name="theme-color" content="#618fc3" meta name="theme-color" content="#618fc3"
meta name="format-detection" content="telephone=no" meta name="format-detection" content="telephone=no"
= csrf_meta_tag() = csrf_meta_tag()
script type="text/javascript" src=Routes.static_path(@conn, "/js/app.js") async="async" script type="module" src=Routes.static_path(@conn, "/js/app.js") async="async"
= render PhilomenaWeb.LayoutView, "_opengraph.html", assigns = render PhilomenaWeb.LayoutView, "_opengraph.html", assigns
body data-theme=theme_name(@current_user) body data-theme=theme_name(@current_user)
= render PhilomenaWeb.LayoutView, "_burger.html", assigns = render PhilomenaWeb.LayoutView, "_burger.html", assigns