mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-25 09:47:30 +00:00
99d9b0f728
Instead of statically hardcoding every frontend asset, this uses a type-based approach to cache all js,css and manifest.json requests. This also fixes the issue that the service worker was interfering with EventSource because it was unconditionally handling all requests which this new implementation doesn't. Fixes: https://github.com/go-gitea/gitea/issues/11092 Fixes: https://github.com/go-gitea/gitea/issues/7372
269 lines
7.1 KiB
JavaScript
269 lines
7.1 KiB
JavaScript
const cssnano = require('cssnano');
|
|
const fastGlob = require('fast-glob');
|
|
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
|
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
|
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
|
const PostCSSPresetEnv = require('postcss-preset-env');
|
|
const PostCSSSafeParser = require('postcss-safe-parser');
|
|
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
|
|
const TerserPlugin = require('terser-webpack-plugin');
|
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
|
const {statSync} = require('fs');
|
|
const {resolve, parse} = require('path');
|
|
const {SourceMapDevToolPlugin} = require('webpack');
|
|
|
|
const glob = (pattern) => fastGlob.sync(pattern, {cwd: __dirname, absolute: true});
|
|
|
|
const themes = {};
|
|
for (const path of glob('web_src/less/themes/*.less')) {
|
|
themes[parse(path).name] = [path];
|
|
}
|
|
|
|
const isProduction = process.env.NODE_ENV !== 'development';
|
|
|
|
module.exports = {
|
|
mode: isProduction ? 'production' : 'development',
|
|
entry: {
|
|
index: [
|
|
resolve(__dirname, 'web_src/js/index.js'),
|
|
resolve(__dirname, 'web_src/less/index.less'),
|
|
],
|
|
swagger: [
|
|
resolve(__dirname, 'web_src/js/standalone/swagger.js'),
|
|
],
|
|
jquery: [
|
|
resolve(__dirname, 'web_src/js/jquery.js'),
|
|
],
|
|
serviceworker: [
|
|
resolve(__dirname, 'web_src/js/serviceworker.js'),
|
|
],
|
|
icons: glob('node_modules/@primer/octicons/build/svg/**/*.svg'),
|
|
...themes,
|
|
},
|
|
devtool: false,
|
|
output: {
|
|
path: resolve(__dirname, 'public'),
|
|
filename: ({chunk}) => {
|
|
// serviceworker can only manage assets below it's script path so we
|
|
// have to put it in / instead of /js/
|
|
return chunk.id === 'serviceworker' ? '[name].js' : 'js/[name].js';
|
|
},
|
|
chunkFilename: 'js/[name].js',
|
|
},
|
|
optimization: {
|
|
minimize: isProduction,
|
|
minimizer: [
|
|
new TerserPlugin({
|
|
sourceMap: true,
|
|
extractComments: false,
|
|
terserOptions: {
|
|
keep_fnames: /^(HTML|SVG)/, // https://github.com/fgnass/domino/issues/144
|
|
output: {
|
|
comments: false,
|
|
},
|
|
},
|
|
}),
|
|
new OptimizeCSSAssetsPlugin({
|
|
cssProcessor: cssnano,
|
|
cssProcessorOptions: {
|
|
parser: PostCSSSafeParser,
|
|
},
|
|
cssProcessorPluginOptions: {
|
|
preset: [
|
|
'default',
|
|
{
|
|
discardComments: {
|
|
removeAll: true,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
splitChunks: {
|
|
chunks: 'async',
|
|
name: (_, chunks) => chunks.map((item) => item.name).join('-'),
|
|
cacheGroups: {
|
|
// this bundles all monaco's languages into one file instead of emitting 1-65.js files
|
|
monaco: {
|
|
test: /monaco-editor/,
|
|
name: 'monaco',
|
|
chunks: 'async'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
module: {
|
|
rules: [
|
|
{
|
|
test: /\.vue$/,
|
|
exclude: /node_modules/,
|
|
loader: 'vue-loader',
|
|
},
|
|
{
|
|
test: require.resolve('jquery-datetimepicker'),
|
|
use: 'imports-loader?define=>false,exports=>false',
|
|
},
|
|
{
|
|
test: /\.worker\.js$/,
|
|
exclude: /monaco/,
|
|
use: [
|
|
{
|
|
loader: 'worker-loader',
|
|
options: {
|
|
name: '[name].js',
|
|
inline: true,
|
|
fallback: false,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
test: /\.js$/,
|
|
exclude: /node_modules/,
|
|
use: [
|
|
{
|
|
loader: 'babel-loader',
|
|
options: {
|
|
cacheDirectory: true,
|
|
cacheCompression: false,
|
|
cacheIdentifier: [
|
|
resolve(__dirname, 'package.json'),
|
|
resolve(__dirname, 'package-lock.json'),
|
|
resolve(__dirname, 'webpack.config.js'),
|
|
].map((path) => statSync(path).mtime.getTime()).join(':'),
|
|
sourceMaps: true,
|
|
presets: [
|
|
[
|
|
'@babel/preset-env',
|
|
{
|
|
useBuiltIns: 'usage',
|
|
corejs: 3,
|
|
},
|
|
],
|
|
],
|
|
plugins: [
|
|
[
|
|
'@babel/plugin-transform-runtime',
|
|
{
|
|
regenerator: true,
|
|
}
|
|
],
|
|
'@babel/plugin-proposal-object-rest-spread',
|
|
],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
test: /\.(less|css)$/i,
|
|
use: [
|
|
{
|
|
loader: MiniCssExtractPlugin.loader,
|
|
},
|
|
{
|
|
loader: 'css-loader',
|
|
options: {
|
|
importLoaders: 2,
|
|
url: (_url, resourcePath) => {
|
|
// only resolve URLs for dependencies
|
|
return resourcePath.includes('node_modules');
|
|
},
|
|
}
|
|
},
|
|
{
|
|
loader: 'postcss-loader',
|
|
options: {
|
|
plugins: () => [
|
|
PostCSSPresetEnv(),
|
|
],
|
|
},
|
|
},
|
|
{
|
|
loader: 'less-loader',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
test: /\.svg$/,
|
|
use: [
|
|
{
|
|
loader: 'svg-sprite-loader',
|
|
options: {
|
|
extract: true,
|
|
spriteFilename: 'img/svg/icons.svg',
|
|
symbolId: (path) => {
|
|
const {name} = parse(path);
|
|
if (/@primer[/\\]octicons/.test(path)) {
|
|
return `octicon-${name}`;
|
|
}
|
|
return name;
|
|
},
|
|
},
|
|
},
|
|
{
|
|
loader: 'svgo-loader',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
test: /\.(ttf|woff2?)$/,
|
|
use: [
|
|
{
|
|
loader: 'file-loader',
|
|
options: {
|
|
name: '[name].[ext]',
|
|
outputPath: 'fonts/',
|
|
publicPath: (url) => `../fonts/${url}`, // seems required for monaco's font
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
plugins: [
|
|
new VueLoaderPlugin(),
|
|
// avoid generating useless js output files for css- and svg-only chunks
|
|
new FixStyleOnlyEntriesPlugin({
|
|
extensions: ['less', 'scss', 'css', 'svg'],
|
|
silent: true,
|
|
}),
|
|
new MiniCssExtractPlugin({
|
|
filename: 'css/[name].css',
|
|
chunkFilename: 'css/[name].css',
|
|
}),
|
|
new SourceMapDevToolPlugin({
|
|
filename: 'js/[name].js.map',
|
|
include: [
|
|
'js/index.js',
|
|
],
|
|
}),
|
|
new SpriteLoaderPlugin({
|
|
plainSprite: true,
|
|
}),
|
|
new MonacoWebpackPlugin({
|
|
filename: 'js/monaco-[name].worker.js',
|
|
}),
|
|
],
|
|
performance: {
|
|
hints: false,
|
|
maxEntrypointSize: Infinity,
|
|
maxAssetSize: Infinity,
|
|
},
|
|
resolve: {
|
|
symlinks: false,
|
|
alias: {
|
|
vue$: 'vue/dist/vue.esm.js', // needed because vue's default export is the runtime only
|
|
},
|
|
},
|
|
watchOptions: {
|
|
ignored: [
|
|
'node_modules/**',
|
|
],
|
|
},
|
|
stats: {
|
|
children: false,
|
|
},
|
|
};
|