build: use esbuild to bundle the web app (#6280)

This commit is contained in:
Charles Kerr 2023-11-27 19:23:40 -06:00 committed by GitHub
parent b00b8dd2fb
commit b9d1b33939
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1316 additions and 4775 deletions

View File

@ -111,9 +111,12 @@ jobs:
echo
echo Please undo your changes to these files:
git diff --exit-code --name-only --merge-base "origin/$GITHUB_BASE_REF" -- \
web/public_html/transmission-app.css \
web/public_html/transmission-app.css.LEGAL.txt \
web/public_html/transmission-app.css.map \
web/public_html/transmission-app.js \
web/public_html/transmission-app.js.map \
web/public_html/transmission-app.js.LICENSE.txt
web/public_html/transmission-app.js.LEGAL.txt \
web/public_html/transmission-app.js.map
update-generated-files:
runs-on: ubuntu-latest

View File

@ -9,10 +9,6 @@ module.exports = {
"plugin:sonarjs/recommended",
"plugin:unicorn/recommended"
],
"parser": "@babel/eslint-parser",
"parserOptions": {
"sourceType": "module"
},
"plugins": [
"sonarjs",
"unicorn"

View File

@ -53,18 +53,20 @@ set(WEB_IMAGES
add_custom_command(
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.css"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.css.LEGAL.txt"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.css.map"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js.LEGAL.txt"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js.map"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js.LICENSE.txt"
WORKING_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}"
COMMAND "${CMAKE_COMMAND}" -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/babel.config.js"
"${CMAKE_CURRENT_SOURCE_DIR}/esbuild.mjs"
"${CMAKE_CURRENT_SOURCE_DIR}/package-lock.json"
"${CMAKE_CURRENT_SOURCE_DIR}/package.json"
"${CMAKE_CURRENT_SOURCE_DIR}/prettier.config.js"
"${CMAKE_CURRENT_SOURCE_DIR}/stylelint.config.js"
"${CMAKE_CURRENT_SOURCE_DIR}/webpack.config.js"
"${CMAKE_CURRENT_BINARY_DIR}"
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/assets" "assets"
@ -82,9 +84,12 @@ add_custom_command(
add_custom_target("${TR_NAME}-web"
ALL
DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.css"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.css.LEGAL.txt"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.css.map"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js.LEGAL.txt"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js.map"
"${CMAKE_CURRENT_BINARY_DIR}/public_html/transmission-app.js.LICENSE.txt"
SOURCES
${WEB_SOURCES})

View File

@ -1,19 +0,0 @@
# Transmission Web Client
A web interface is built into all Transmission flavors, enabling them to be controlled remotely.
## Developing locally
First, in this web directory, run `npm i` to install all dependencies. (Youll need to have node and npm installed, of course.)
Run `npm run dev` to compile the source javascript files into a bundle, then navigate to [localhost:9000](http://localhost:9000/).
Webpack will automatically compile on save, so you should see any changes reflected immediately.
## Anonymizing your data for screenshots
Use this bookmarklet to anonymize your torrent names before submitting a screenshot:
`javascript:void%20function(){const%20a=document.getElementsByClassName(%22torrent-name%22);for(const%20b%20of%20a)console.log(b),b.textContent=%22Lorem%20ipsum%20dolor%20sit%20amet.iso%22}();`
Youll typically have about 3 seconds before the next batch of RPC updates overwrite the text content of any currently-downloading files.

55
web/README.md Normal file
View File

@ -0,0 +1,55 @@
# Transmission Web Client
A web interface is built into all Transmission flavors, enabling them to be controlled remotely.
## Notes for Packagers
### Building Without Node
Transmission includes a prebuilt webapp bundle in its releases. This is
done because it's not easy to install the bundling tools on all of the
platforms that Transmission supports. Debian can't use this prebuilt
bundle due to its (understandable) policies that require building from
source. Unfortunately, building with `node run build` is also problematic
because of some of `package.json`'s `devDependencies` aren't available as
Debian packages.
Follow these steps to build the webapp from source on Debian without Node:
```sh
$ sudo apt install rsass perl esbuild
$ cd transmission/web/
$ rsass assets/css/transmission-app.scss > assets/css/transmission-app.css
$ perl -p -i -e 's/transmission-app.scss/transmission-app.css/' src/main.js
$ esbuild \
--allow-overwrite \
--bundle \
--legal-comments=external \
--loader:.png=binary \
--loader:.svg=binary \
--minify \
--outfile=public_html/transmission-app.js \
src/main.js
```
## Notes for Developers
```sh
$ npm install
$ npm run dev
```
Navigate to [localhost:9000](http://localhost:9000/) to run the app.
When you use `npm run dev`, the bundler will stay running in the
background and will rebuild transmission-app.js whenever you change
and save a source file. When it's done, you can reload the page in
your browser to see your changes in action.
## Notes for Testers
Use this bookmarklet to anonymize your torrent names before submitting a screenshot:
`javascript:void%20function(){const%20a=document.getElementsByClassName(%22torrent-name%22);for(const%20b%20of%20a)console.log(b),b.textContent=%22Lorem%20ipsum%20dolor%20sit%20amet.iso%22}();`
Youll typically have about 3 seconds before the next batch of RPC updates overwrite the text content of any currently-downloading files.

View File

@ -1,6 +0,0 @@
module.exports = {
"plugins": [
"@babel/plugin-transform-class-properties"
],
"presets": []
};

24
web/esbuild.mjs Normal file
View File

@ -0,0 +1,24 @@
import * as esbuild from 'esbuild';
import * as process from 'node:process';
import {sassPlugin} from 'esbuild-sass-plugin';
const ctx = await esbuild.context({
bundle: true,
entryPoints: ['./src/main.js'],
legalComments: 'external',
loader: {
'.png': 'binary',
'.svg': 'binary' },
minify: true,
outfile: './public_html/transmission-app.js',
plugins: [sassPlugin()],
sourcemap: true,
});
if (process.env.DEV) {
await ctx.watch();
console.log('watching...');
} else {
await ctx.rebuild();
ctx.dispose();
}

5834
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,8 @@
"repository": "https://github.com/transmission/transmission",
"license": "MIT",
"scripts": {
"dev": "WEBPACK_MODE=development webpack serve --config webpack.config.js",
"build": "webpack --config webpack.config.js",
"css": "sass --no-source-map assets/css/",
"css:map": "sass assets/css/",
"build": "node esbuild.mjs",
"dev": "DEV=true node esbuild.mjs",
"lint": "run-p --silent lint:eslint lint:stylelint lint:prettier",
"lint:fix": "run-s lint:eslint:fix lint:stylelint:fix lint:prettier:fix",
"lint:eslint": "eslint src/*.js",
@ -18,30 +16,19 @@
"lint:stylelint:fix": "stylelint --fix assets/css/*scss"
},
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/eslint-parser": "^7.22.15",
"@babel/plugin-transform-class-properties": "^7.22.5",
"esbuild": "^0.19.7",
"esbuild-sass-plugin": "^2.16.0",
"@primer/stylelint-config": "^12.8.0",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"eslint": "^8.45.0",
"eslint-plugin-sonarjs": "^0.19.0",
"eslint-plugin-unicorn": "^47.0.0",
"file-loader": "^6.2.0",
"mini-css-extract-plugin": "^2.7.6",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.0",
"sass": "^1.63.6",
"sass-loader": "^13.2.2",
"style-loader": "^3.3.3",
"stylelint": "^15.10.1",
"stylelint-config-sass-guidelines": "^10.0.0",
"stylelint-config-standard": "^34.0.0",
"terser-webpack-plugin": "^5.3.9",
"webpack": "^5.88.1",
"webpack-bundle-analyzer": "^4.9.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
"stylelint-config-standard": "^34.0.0"
},
"dependencies": {
"lodash.isequal": "^4.5.0"

View File

@ -0,0 +1,16 @@
{
"name": "transmission-web",
"main": "index.js",
"repository": "https://github.com/transmission/transmission",
"license": "MIT",
"scripts": {
"build": "node esbuild.mjs"
},
"devDependencies": {
"esbuild": "^0.19.7",
"esbuild-sass-plugin": "^2.16.0"
},
"dependencies": {
"lodash.isequal": "^4.5.0"
}
}

View File

@ -9,6 +9,7 @@
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link href="./transmission-app.css" rel="stylesheet" />
<link href="./images/favicon.ico" rel="icon" />
<link href="./images/favicon.png" rel="shortcut icon" />
<link rel="apple-touch-icon" href="./images/webclip-icon.png" />

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,7 @@
/* @license This file Copyright © Charles Kerr, Dave Perrett, Malcolm Jarvis and Bruno Bierbaumer
It may be used under GPLv2 (SPDX: GPL-2.0-only).
License text can be found in the licenses/ folder. */
/* @license This file Copyright © Mnemosyne LLC.
It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
or any future license endorsed by Mnemosyne LLC.
License text can be found in the licenses/ folder. */
/* @license This file Copyright © Charles Kerr, Dave Perrett, Malcolm Jarvis and Bruno Bierbaumer
It may be used under GPLv2 (SPDX: GPL-2.0-only).
License text can be found in the licenses/ folder. */

View File

@ -1,73 +0,0 @@
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
const mode = process.env.WEBPACK_MODE || 'production';
const devPort = process.env.DEV_PORT || 9000;
const rpcUrl = process.env.RPC_URL || 'http://localhost:9091/transmission/rpc';
const config = {
devtool: 'source-map',
entry: './src/main.js',
mode,
module: {
rules: [
{
test: /\.s(a|c)ss$/,
use: [
'style-loader', // create 'style' nodes from JS strings
'css-loader', // translate css into commonjs
'sass-loader', // compile sass into css
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg)/,
type: 'asset/inline',
},
],
},
optimization: {
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
},
output: {
filename: 'transmission-app.js',
path: path.resolve(__dirname, 'public_html'),
sourceMapFilename: '[file].map',
},
plugins: [
new MiniCssExtractPlugin({
chunkFilename: '[id].css',
filename: '[name].css',
}),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
],
resolve: {
extensions: ['.js', '.scss'],
},
};
if (mode === 'development') {
config.devServer = {
compress: true,
historyApiFallback: {
rewrites: [{ from: '/transmission/web', to: '/' }],
},
hot: true,
port: devPort,
proxy: {
'/rpc': rpcUrl,
},
static: './public_html',
};
}
module.exports = config;