@@ -1,25 +1,24 @@
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});
import fastGlob from 'fast-glob';
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 {fileURLToPath} from 'node:url';
import {readFileSync} from 'node:fs';
import TerserPlugin from "terser-webpack-plugin"
const { ESBuildMinifyPlugin } = EsBuildLoader;
const { SourceMapDevToolPlugin } = webpack;
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/less/themes/*.less')) {
themes[parse(path).name] = [path];
}
const standalone = {};
const stadalonePaths = [
...glob('web_src/js/standalone/**/*.js'),
@@ -28,14 +27,12 @@ const stadalonePaths = [
for (const path of stadalonePaths) {
standalone[parse(path).name] = [path];
}
const vuePages = {};
for (const path of glob('web_src/vuepages/**/vp-*.js')) {
vuePages[parse(path).name] = [path];
}
const isProduction = process.env.NODE_ENV !== 'development';
let isWatching = false;
for (let arg in process.argv) {
if (process.argv[arg] == '--watch') {
@@ -44,59 +41,45 @@ for (let arg in process.argv) {
}
}
module.exports = {
/** @type {import("webpack").Configuration} */
export default {
mode: isProduction ? 'production' : 'development',
entry: {
index: [
resolve(__dirname, 'web_src/js/index.js' ),
resolve(__dirname, 'web_src/less/index.less' ),
fileURLToPath(new URL('web_src/js/index.js', import.meta.url) ),
fileURLToPath(new URL('web_src/less/index.less', import.meta.url) ),
],
jquery: [
resolve(__dirname, 'web_src/js/jquery.js' ),
fileURLToPath(new URL('web_src/js/jquery.js', import.meta.url) ),
],
icons: glob('node_modules/@primer/octicons/build/svg/**/*.svg'),
...standalone,
...themes,
...vuePages,
...vuePages
},
devtool: false,
output: {
path: resolve(__dirname, 'public'),
filename: 'js/[name].js',
path: fileURLToPath(new URL('public', import.meta.url)),
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',
},
node:{
fs: 'empty'
},
optimization: {
minimize: fals e,
minimize: true,
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,
},
},
],
},
new ESBuildMinifyPlugin({
target: 'es2015',
minify: true,
css: true,
legalComments: 'none',
}),
// new TerserPlugin({
// extractComments: false,
// }),
],
splitChunks: {
chunks: 'async',
@@ -109,7 +92,9 @@ module.exports = {
chunks: 'async'
}
}
}
},
moduleIds: 'named',
chunkIds: 'named',
},
module: {
rules: [
@@ -118,10 +103,6 @@ module.exports = {
exclude: /node_modules/,
loader: 'vue-loader',
},
{
test: require.resolve('jquery-datetimepicker'),
use: 'imports-loader?define=>false,exports=>false',
},
{
test: /\.worker\.js$/,
exclude: /monaco/,
@@ -129,61 +110,32 @@ module.exports = {
{
loader: 'worker-loader',
options: {
name: '[name].js',
inline: true,
fallback: false,
inline: 'no-fallback',
},
},
],
},
{
test: /\.ts$/,
use: [
{
loader: "ts-loader",
}
],
exclude: /node_modules/
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified:false
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'bab el-loader',
loader: 'esbui ld -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',
],
target: 'es2015'
},
},
],
},
{
test: /\ .(less| css) $/i,
test: /.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
@@ -192,32 +144,70 @@ module.exports = {
loader: 'css-loader',
options: {
importLoaders: 2,
url: (_url, resourcePath) => {
// only resolve URLs for dependencies
url: {
filter: (url, resourcePath) => {
// only resolve URLs for dependencies
return resourcePath.includes('node_modules');
},
},
}
}
},
],
},
{
test: /.less$/i,
use: [
{
loader: 'postcss-loader',
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
plugins: () => [
PostCSSPresetEnv(),
],
sourceMap: true,
importLoaders: 2,
url: {
filter: (url, resourcePath) => {
// only resolve URLs for dependencies
return resourcePath.includes('node_modules');
},
}
},
},
{
loader: 'less-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.(ttf|woff2?)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[ext]',
}
},
{
test: /\.(png|jpg|gif)$/,
type: 'asset/resource',
generator: {
filename: 'img/webpack/[name].[ext]',
}
},
{
test: /\.json$/,
type: 'json',
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
// extract: true,
spriteFilename: 'img/svg/icons.svg',
symbolId: (path) => {
const {name} = parse(path);
@@ -233,36 +223,10 @@ module.exports = {
},
],
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-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',
@@ -273,14 +237,13 @@ module.exports = {
'js/index.js',
/js\/vp-.*\.js/,
],
})] : [])
,
new SpriteLoaderPlugin({
plainSprite: true,
}),
})] : []),
new MonacoWebpackPlugin({
filename: 'js/monaco-[name].worker.js',
})
}),
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer']
}),
],
performance: {
hints: false,
@@ -291,9 +254,9 @@ module.exports = {
symlinks: false,
alias: {
vue$: 'vue/dist/vue.esm.js', // needed because vue's default export is the runtime only
'~': resolve(__dirname, 'web_src/vuepages'),
'~': fileURLToPath(new URL('web_src/vuepages', import.meta.url))
},
extensions: ['.tsx ', '.ts', '.js']
extensions: ['.vue ', '.ts', '.js']
},
watchOptions: {
ignored: [
@@ -301,6 +264,23 @@ module.exports = {
],
},
stats: {
assetsSort: 'name',
assetsSpace: Infinity,
cached: false,
cachedModules: false,
children: false,
chunkModules: false,
chunkOrigins: false,
chunksSort: 'name',
colors: true,
entrypoints: false,
groupAssetsByChunk: false,
groupAssetsByEmitStatus: false,
groupAssetsByInfo: false,
groupModulesByAttributes: false,
modules: false,
reasons: false,
runtimeModules: false,
},
};