bc4f7ba69b
* Add automatic JS license generation Removed librejs file and replaced it with a plaintext file that is built from all JS dependencies that are included in the webpack build. It does not cover the few remaining statically vendored files and fomantic is added manually because it's not yet in the webpack build process. Fixes: https://github.com/go-gitea/gitea/issues/11630 * fix lint * remove jslicense, we're not librejs compatible any more * remove license.txt test as it depens on absent files * small optimization * trailing comma * localize and capitalize the word 'licenses' * reduce text to just 'Licenses' Co-authored-by: Lauris BH <lauris@nix.lv>
294 lines
7.9 KiB
JavaScript
294 lines
7.9 KiB
JavaScript
const cssnano = require('cssnano');
|
|
const fastGlob = require('fast-glob');
|
|
const wrapAnsi = require('wrap-ansi');
|
|
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 {LicenseWebpackPlugin} = require('license-webpack-plugin');
|
|
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's directory so
|
|
// we have to put it in / instead of /js/
|
|
return chunk.name === '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: /\.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',
|
|
}),
|
|
new LicenseWebpackPlugin({
|
|
outputFilename: 'js/licenses.txt',
|
|
perChunkOutput: false,
|
|
addBanner: false,
|
|
skipChildCompilers: true,
|
|
modulesDirectories: [
|
|
resolve(__dirname, 'node_modules'),
|
|
],
|
|
additionalModules: [
|
|
{
|
|
name: 'fomantic-ui',
|
|
directory: resolve(__dirname, 'node_modules/fomantic-ui'),
|
|
},
|
|
],
|
|
renderLicenses: (modules) => {
|
|
const line = '-'.repeat(80);
|
|
return modules.map((module) => {
|
|
const {name, version} = module.packageJson;
|
|
const {licenseId, licenseText} = module;
|
|
const body = wrapAnsi(licenseText || '', 80);
|
|
return `${line}\n${name}@${version} - ${licenseId}\n${line}\n${body}`;
|
|
}).join('\n');
|
|
},
|
|
stats: {
|
|
warnings: false,
|
|
errors: true,
|
|
},
|
|
}),
|
|
],
|
|
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,
|
|
},
|
|
};
|