upgrade to webpack 5

Web CLI update:
* commander -> cac
* enquirer -> prompts
This commit is contained in:
Pig Fang 2020-11-06 15:37:45 +08:00
parent b07e227e91
commit 34c90b50f2
No known key found for this signature in database
GPG Key ID: A8198F548DADA9E2
20 changed files with 678 additions and 1455 deletions

View File

@ -10,11 +10,11 @@
"license": "MIT",
"private": true,
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack -p --progress && webpack -p --config=webpack.meta.config.ts",
"dev": "webpack serve",
"build": "webpack --env production --progress",
"lint": "eslint --ext=ts -f=beauty .",
"fmt": "prettier --write resources/assets tools webpack.*.ts",
"fmt:check": "prettier --check resources/assets tools webpack.*.ts",
"fmt": "prettier --write resources/assets tools webpack.config.ts",
"fmt:check": "prettier --check resources/assets tools webpack.config.ts",
"test": "jest",
"build:urls": "ts-node tools/generateUrls.ts"
},
@ -23,14 +23,15 @@
"@emotion/styled": "^10.0.27",
"@hot-loader/react-dom": "^17.0.0",
"@tweenjs/tween.js": "^18.5.0",
"blessing-skin-shell": "^0.3.1",
"cli-spinners": "^2.3.0",
"commander": "^5.1.0",
"blessing-skin-shell": "^0.3.4",
"cac": "^6.6.1",
"cli-spinners": "^2.5.0",
"echarts": "^4.7.0",
"enquirer": "^2.3.5",
"events": "^3.2.0",
"immer": "^7.0.4",
"lodash.debounce": "^4.0.8",
"nanoid": "^3.1.9",
"prompts": "^2.4.0",
"react": "^17.0.1",
"react-autosuggest": "^10.0.2",
"react-dom": "^17.0.1",
@ -60,13 +61,12 @@
"@types/jquery": "^3.3.38",
"@types/js-yaml": "^3.12.4",
"@types/lodash.debounce": "^4.0.6",
"@types/mini-css-extract-plugin": "^0.9.1",
"@types/mini-css-extract-plugin": "^1.2.1",
"@types/prompts": "^2.0.9",
"@types/react": "^16.9.35",
"@types/react-autosuggest": "^9.3.14",
"@types/react-dom": "^16.9.8",
"@types/terser-webpack-plugin": "^3.0.0",
"@types/tween.js": "^18.5.0",
"@types/webpack": "^4.41.18",
"@types/webpack-dev-server": "^3.11.0",
"@typescript-eslint/eslint-plugin": "^3.6.0",
"@typescript-eslint/parser": "^3.6.0",
@ -77,7 +77,7 @@
"eslint": "^7.4.0",
"eslint-formatter-beauty": "^3.0.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.0",
"html-webpack-plugin": "next",
"jest": "^26.6.1",
"jest-extended": "^0.11.5",
"jquery": "^3.5.1",
@ -92,10 +92,13 @@
"ts-node": "^8.10.2",
"typescript": "^4.0.2",
"url-loader": "^4.1.1",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack": "^5.4.0",
"webpack-cli": "^4.1.0",
"webpack-dev-server": "^3.11.0"
},
"resolutions": {
"kleur": "^4.1.3"
},
"browserslist": [
"> 1%",
"not dead",

View File

@ -77,6 +77,16 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
shell.addExternal(name, program)
})
const originalLogger = console.log
console.log = (data: string, ...args: any[]) => {
const stack = new Error().stack
if (stack?.includes('outputHelp')) {
terminal.writeln(data.replace(/\n/g, '\r\n'))
} else {
originalLogger(data, ...args)
}
}
const unbindData = terminal.onData((e) => shell.input(e))
const unbindKey = terminal.onKey((e) =>
event.emit('terminalKeyPress', e.key),
@ -89,6 +99,7 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
shell.free()
fitAddon.dispose()
terminal.dispose()
console.log = originalLogger
launched = false
}
}, [])
@ -98,7 +109,9 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
<TerminalContainer className="card">
<div className="card-header">
<div className="d-flex justify-content-between">
<h4 className="card-title mt-1">Blessing Skin Shell</h4>
<h4 className="card-title d-flex align-items-center">
Blessing Skin Shell
</h4>
<button className="btn btn-default" onClick={props.onClose}>
&times;
</button>

View File

@ -1,33 +1,23 @@
import type { Stdio } from 'blessing-skin-shell'
import { Command } from 'commander'
import { hackStdout, overrideExit } from './configureStdio'
import cac from 'cac'
import { install, remove } from './pluginManager'
export default async function apt(stdio: Stdio, args: string[]) {
const program = new Command()
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
process.stdout = hackStdout(stdio)
overrideExit(program, stdio)
}
program.name(apt.name)
const program = cac('apt')
program.help()
program
.command('install <plugin>')
.description('install a new plugin')
.command('install <plugin>', 'install a new plugin')
.action((plugin: string) => install(plugin, stdio))
program
.command('upgrade <plugin>')
.description('upgrade an existed plugin')
.command('upgrade <plugin>', 'upgrade an existed plugin')
.action((plugin: string) => install(plugin, stdio))
program
.command('remove <plugin>')
.description('remove a plugin')
.command('remove <plugin>', 'remove a plugin')
.action((plugin: string) => remove(plugin, stdio))
await program.parseAsync(args, { from: 'user' })
program.parse(['', ''].concat(args), { run: false })
await program.runMatchedCommand()
}

View File

@ -1,24 +1,16 @@
import type { Stdio } from 'blessing-skin-shell'
import { Command } from 'commander'
import cac from 'cac'
import * as fetch from '../net'
import { User, Texture } from '../types'
import { hackStdout, overrideExit } from './configureStdio'
type Response = fetch.ResponseBody<{ user: User; texture: Texture }>
export default async function closet(stdio: Stdio, args: string[]) {
const program = new Command()
const program = cac('closet')
program.help()
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
process.stdout = hackStdout(stdio)
overrideExit(program, stdio)
}
program.name('closet').version('0.1.0')
program
.command('add <uid> <tid>')
.description("add texture to someone's closet")
.command('add <uid> <tid>', "add texture to someone's closet")
.action(async (uid: string, tid: string) => {
const { code, data } = await fetch.post<Response>(
`/admin/closet/${uid}`,
@ -34,8 +26,7 @@ export default async function closet(stdio: Stdio, args: string[]) {
}
})
program
.command('remove <uid> <tid>')
.description("remove texture from someone's closet")
.command('remove <uid> <tid>', "remove texture from someone's closet")
.action(async (uid: string, tid: string) => {
const { code, data } = await fetch.del<Response>(`/admin/closet/${uid}`, {
tid,
@ -50,5 +41,6 @@ export default async function closet(stdio: Stdio, args: string[]) {
}
})
await program.parseAsync(args, { from: 'user' })
program.parse(['', ''].concat(args), { run: false })
await program.runMatchedCommand()
}

View File

@ -1,33 +1,23 @@
import type { Stdio } from 'blessing-skin-shell'
import { Command } from 'commander'
import { hackStdout, overrideExit } from './configureStdio'
import cac from 'cac'
import { install, remove } from './pluginManager'
export default async function dnf(stdio: Stdio, args: string[]) {
const program = new Command()
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
process.stdout = hackStdout(stdio)
overrideExit(program, stdio)
}
program.name(dnf.name)
const program = cac('dnf')
program.help()
program
.command('install <plugin>')
.description('install a new plugin')
.command('install <plugin>', 'install a new plugin')
.action((plugin: string) => install(plugin, stdio))
program
.command('upgrade <plugin>')
.description('upgrade an existed plugin')
.command('upgrade <plugin>', 'upgrade an existed plugin')
.action((plugin: string) => install(plugin, stdio))
program
.command('remove <plugin>')
.description('remove a plugin')
.command('remove <plugin>', 'remove a plugin')
.action((plugin: string) => remove(plugin, stdio))
await program.parseAsync(args, { from: 'user' })
program.parse(['', ''].concat(args), { run: false })
await program.runMatchedCommand()
}

View File

@ -1,6 +1,5 @@
import type { Stdio } from 'blessing-skin-shell'
import { Command } from 'commander'
import { hackStdout, overrideExit } from './configureStdio'
import cac from 'cac'
import { install, remove } from './pluginManager'
type Options = {
@ -14,24 +13,15 @@ export default async function pacman(stdio: Stdio, args: string[]) {
return
}
const program = new Command()
const program = cac('pacman')
program.help()
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
process.stdout = hackStdout(stdio)
overrideExit(program, stdio)
}
program.option('-S, --sync <plugin>', 'install or upgrade a plugin')
program.option('-R, --remove <plugin>', 'remove a plugin')
program.name(pacman.name)
const { options } = program.parse(['', ''].concat(args), { run: false })
program
.option('-S, --sync <plugin>')
.description('install or upgrade a plugin')
program.option('-R, --remove <plugin>').description('remove a plugin')
program.parse(args, { from: 'user' })
const opts: Options = program.opts()
const opts: Options = options
/* istanbul ignore else */
if (opts.sync) {
await install(opts.sync, stdio)

View File

@ -1,24 +1,19 @@
import type { Stdio } from 'blessing-skin-shell'
import { Command } from 'commander'
import cac from 'cac'
import * as fetch from '../net'
import { hackStdout, overrideExit } from './configureStdio'
type Options = {
force?: boolean
recursive?: boolean
help?: boolean
}
export default async function rm(stdio: Stdio, args: string[]) {
const program = new Command()
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
process.stdout = hackStdout(stdio)
overrideExit(program, stdio)
}
const program = cac('rm')
program.help()
program
.name('rm')
.command('<file>')
.option(
'-f, --force',
'ignore nonexistent files and arguments, never prompt',
@ -28,12 +23,12 @@ export default async function rm(stdio: Stdio, args: string[]) {
'remove directories and their contents recursively',
)
.option('--no-preserve-root', "do not treat '/' specially")
.arguments('<file>')
const opts: Options = program.parse(args, { from: 'user' }).opts()
const opts: Options = program.parse(['', ''].concat(args), { run: false })
.options
const path = program.args[0]
if (!path) {
if (!path && !opts.help) {
stdio.println('rm: missing operand')
stdio.println("Try 'rm --help' for more information.")
}

View File

@ -1,5 +1,7 @@
import type { Stdio } from 'blessing-skin-shell'
import { dots } from 'cli-spinners'
import spinners from 'cli-spinners/spinners.json'
const { dots } = spinners
export class Spinner {
private timerId = 0

View File

@ -1,5 +1,4 @@
import { Stdio } from 'blessing-skin-shell'
import type Commander from 'commander'
import * as event from '../event'
/* istanbul ignore next */
@ -10,10 +9,10 @@ export function hackStdin() {
// @ts-ignore
return {
on(eventName: string, handler: (key: string) => void) {
on(eventName: string, handler: (str: string, key: string) => void) {
if (eventName === 'keypress') {
this._off = event.on('terminalKeyPress', (key: string) => {
handler(key)
handler(key, key)
})
}
},
@ -34,14 +33,3 @@ export function hackStdout(stdio: Stdio) {
},
} as NodeJS.WriteStream
}
/* istanbul ignore next */
export function overrideExit(program: Commander.Command, stdio: Stdio) {
Error.captureStackTrace = () => {}
return program.exitOverride((error) => {
if (!error.message.startsWith('(')) {
stdio.print(error.message.replace(/\n/g, '\r\n'))
}
})
}

View File

@ -1,5 +1,5 @@
import type { Stdio } from 'blessing-skin-shell'
import { prompt } from 'enquirer'
import prompts from 'prompts'
import * as fetch from '../net'
import { hackStdout, hackStdin } from './configureStdio'
import { Spinner } from './Spinner'
@ -20,7 +20,7 @@ export async function install(plugin: string, stdio: Stdio) {
}
export async function remove(plugin: string, stdio: Stdio) {
const { confirm }: { confirm: boolean } = await prompt({
const { confirm }: { confirm: boolean } = await prompts({
name: 'confirm',
type: 'confirm',
message: `Are you sure to remove plugin "${plugin}"?`,

View File

@ -3,6 +3,7 @@ declare let __webpack_public_path__: string
if (process.env.NODE_ENV === 'development') {
const url = new URL(blessing.base_url)
url.port = '8080'
url.pathname = '/app/'
__webpack_public_path__ = url.toString()
} else {
const link = document.querySelector<HTMLLinkElement>('link#cdn-host')

View File

@ -50,7 +50,7 @@ describe('remove plugin', () => {
it('cancelled', async () => {
const stdio = new Stdio()
setImmediate(() => process.stdin.emit('keypress', 'n'))
setImmediate(() => process.stdin.emit('keypress', 'n', 'n'))
await apt(stdio, ['remove', 'test'])
expect(fetch.post).not.toBeCalled()
})
@ -59,7 +59,7 @@ describe('remove plugin', () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
setImmediate(() => process.stdin.emit('keypress', 'y'))
setImmediate(() => process.stdin.emit('keypress', 'y', 'y'))
await apt(stdio, ['remove', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',

View File

@ -50,7 +50,7 @@ describe('remove plugin', () => {
it('cancelled', async () => {
const stdio = new Stdio()
setImmediate(() => process.stdin.emit('keypress', 'n'))
setImmediate(() => process.stdin.emit('keypress', 'n', 'n'))
await dnf(stdio, ['remove', 'test'])
expect(fetch.post).not.toBeCalled()
})
@ -59,7 +59,7 @@ describe('remove plugin', () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
setImmediate(() => process.stdin.emit('keypress', 'y'))
setImmediate(() => process.stdin.emit('keypress', 'y', 'y'))
await dnf(stdio, ['remove', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',

View File

@ -46,7 +46,7 @@ describe('remove plugin', () => {
it('cancelled', async () => {
const stdio = new Stdio()
setImmediate(() => process.stdin.emit('keypress', 'n'))
setImmediate(() => process.stdin.emit('keypress', 'n', 'n'))
await pacman(stdio, ['-R', 'test'])
expect(fetch.post).not.toBeCalled()
})
@ -55,7 +55,7 @@ describe('remove plugin', () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
setImmediate(() => process.stdin.emit('keypress', 'y'))
setImmediate(() => process.stdin.emit('keypress', 'y', 'y'))
await pacman(stdio, ['-R', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',

View File

@ -2,35 +2,31 @@ import { promises as fs } from 'fs'
import * as path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import type { Compiler } from 'webpack'
import type { Options } from 'html-webpack-plugin'
class HtmlWebpackEnhancementPlugin {
apply(compiler: Compiler) {
compiler.hooks.assetEmitted.tapPromise(
'HtmlWebpackEnhancementPlugin',
async (name, { source }) => {
if (name.endsWith('.twig')) {
const filePath = path.resolve(
process.cwd(),
'resources',
'views',
'assets',
name,
)
await fs.writeFile(filePath, source.source())
}
},
)
compiler.hooks.compilation.tap(
'HtmlWebpackEnhancementPlugin',
(compilation) => {
const hooks = HtmlWebpackPlugin.getHooks(compilation)
hooks.beforeAssetTagGeneration.tap(
'HtmlWebpackEnhancementPlugin',
(data) => {
// @ts-ignore
const options: Options = data.plugin.options
const entries = (options.templateParameters ?? []) as string[]
data.assets.js = data.assets.js.filter((name) =>
entries.some((entry) =>
new RegExp(`^${entry}\\.`).test(path.basename(name, 'js')),
),
)
data.assets.css = data.assets.css.filter((name) =>
entries.some((entry) =>
new RegExp(`^${entry}\\.`).test(path.basename(name, 'css')),
),
)
return data
},
)
hooks.alterAssetTags.tap('HtmlWebpackEnhancementPlugin', (data) => {
data.assetTags.scripts = data.assetTags.scripts.map((tag) => {
tag.attributes.crossorigin = 'anonymous'
@ -51,29 +47,22 @@ class HtmlWebpackEnhancementPlugin {
compilation.compiler.options.mode === 'production' &&
data.headTags.length > 0
) {
data.bodyTags = data.headTags
if (
data.headTags.some((tag) => tag.attributes.rel === 'stylesheet')
) {
data.bodyTags = data.headTags.filter(
(tag) => tag.tagName !== 'script',
)
} else {
data.bodyTags = data.headTags
}
data.headTags = []
}
return data
},
)
hooks.beforeEmit.tapPromise(
'HtmlWebpackEnhancementPlugin',
async (data) => {
const filePath = path.resolve(
process.cwd(),
'resources',
'views',
'assets',
data.outputName,
)
await fs.writeFile(filePath, data.html)
return data
},
)
},
)
}

24
tools/SyncMetaJsPlugin.ts Normal file
View File

@ -0,0 +1,24 @@
import { promises as fs } from 'fs'
import * as path from 'path'
import type { Compiler } from 'webpack'
class SyncMetaJsPlugin {
apply(compiler: Compiler) {
compiler.hooks.assetEmitted.tapPromise(
'HtmlWebpackEnhancementPlugin',
async (name, { source }) => {
if (compiler.options.mode !== 'development') {
return
}
if (name === 'meta.js' || name === 'sw.js') {
const filePath = path.resolve(process.cwd(), 'public', name)
await fs.writeFile(filePath, source.source())
}
},
)
}
}
export default SyncMetaJsPlugin

View File

@ -8,7 +8,8 @@
"baseUrl": ".",
"paths": {
"@/*": ["./resources/assets/src/*"]
}
},
"resolveJsonModule": true
},
"include": [
"resources/assets/src",

View File

@ -1,150 +1,195 @@
import * as path from 'path'
import * as webpack from 'webpack'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import TerserJSPlugin from 'terser-webpack-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import HtmlWebpackEnhancementPlugin from './tools/HtmlWebpackEnhancementPlugin'
import SyncMetaJsPlugin from './tools/SyncMetaJsPlugin'
const devMode = !process.argv.includes('-p')
interface Env {
production?: boolean
}
const htmlPublicPath = devMode ? '//localhost:8080/' : '{{ cdn_base }}/app/'
export default function (env?: Env): webpack.Configuration[] {
const isDev = !env?.production
const htmlPublicPath = isDev ? '//localhost:8080/app/' : '{{ cdn_base }}/app/'
const config: webpack.Configuration = {
mode: devMode ? 'development' : 'production',
entry: {
app: ['react-hot-loader/patch', '@/index.tsx'],
style: ['@/styles/common.css'],
home: '@/scripts/homePage.ts',
'home-css': '@/styles/home.css',
spectre: [
'spectre.css/dist/spectre.min.css',
'@/fonts/minecraft.css',
'@/styles/spectre.css',
],
},
output: {
path: `${__dirname}/public/app`,
filename: devMode ? '[name].js' : '[name].[contenthash:7].js',
chunkFilename: devMode ? '[id].js' : '[id].[contenthash:7].js',
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
configFile: 'tsconfig.build.json',
transpileOnly: true,
},
},
{
test: /\.css$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
'postcss-loader',
return [
{
name: 'app',
mode: isDev ? 'development' : 'production',
entry: {
app: ['react-hot-loader/patch', '@/index.tsx'],
style: ['@/styles/common.css'],
home: '@/scripts/homePage.ts',
'home-css': '@/styles/home.css',
spectre: [
'spectre.css/dist/spectre.min.css',
'@/fonts/minecraft.css',
'@/styles/spectre.css',
],
},
{
test: /\.(png|webp)$/,
loader: 'url-loader',
options: {
limit: 8192,
},
output: {
path: `${__dirname}/public/app`,
publicPath: '/app/',
filename: isDev ? '[name].js' : '[name].[contenthash:7].js',
chunkFilename: isDev ? '[id].js' : '[id].[contenthash:7].js',
crossOriginLoading: 'anonymous',
},
{
test: /\.(svg|woff2?|eot|ttf)$/,
loader: devMode ? 'url-loader' : 'file-loader',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
configFile: 'tsconfig.build.json',
transpileOnly: true,
},
},
{
test: /\.css$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
'postcss-loader',
],
},
{
test: /\.(png|webp)$/,
loader: 'url-loader',
options: {
limit: 8192,
},
},
{
test: /\.(svg|woff2?|eot|ttf)$/,
loader: isDev ? 'url-loader' : 'file-loader',
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[contenthash:7].css',
chunkFilename: devMode ? '[id].css' : '[id].[contenthash:7].css',
}),
new HtmlWebpackPlugin({
templateContent: devMode
? ''
: `
plugins: [
new MiniCssExtractPlugin({
filename: isDev ? '[name].css' : '[name].[contenthash:7].css',
chunkFilename: isDev ? '[id].css' : '[id].[contenthash:7].css',
}),
new HtmlWebpackPlugin({
templateContent: isDev
? ''
: `
<script src="https://cdn.jsdelivr.net/npm/react@17.0.1/umd/react.production.min.js" integrity="sha256-Ag0WTc8xFszCJo1qbkTKp3wBMdjpjogsZDAhnSge744=" crossorigin></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@17.0.1/umd/react-dom.production.min.js" integrity="sha256-k8tzaSH8ucPwbsHEO4Wk5szE9zERNVz3XQynfyT66O0=" crossorigin></script>`,
templateParameters: ['app'],
filename: 'app.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
templateParameters: ['style'],
filename: 'style.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
templateParameters: ['home'],
filename: 'home.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
templateParameters: ['home-css'],
filename: 'home-css.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
templateParameters: ['spectre'],
filename: 'spectre.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackEnhancementPlugin(),
],
resolve: {
extensions: ['.js', '.ts', '.tsx', '.json'],
alias: {
'react-dom': '@hot-loader/react-dom',
'@': path.resolve(__dirname, 'resources/assets/src'),
readline: '@/scripts/cli/readline.ts',
},
},
externals: Object.assign(
{ jquery: 'jQuery', bootstrap: 'bootstrap', 'admin-lte': 'adminlte' },
devMode
? {}
: {
react: 'React',
'react-dom': 'ReactDOM',
chunks: ['app'],
scriptLoading: 'blocking',
filename: 'app.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
chunks: ['style'],
filename: 'style.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
chunks: ['home'],
scriptLoading: 'blocking',
filename: 'home.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
chunks: ['home-css'],
filename: 'home-css.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackPlugin({
templateContent: '',
chunks: ['spectre'],
filename: 'spectre.twig',
publicPath: htmlPublicPath,
}),
new HtmlWebpackEnhancementPlugin(),
new webpack.DefinePlugin({
'window.Deno': 'true',
Deno: {
args: [],
build: {},
version: {},
},
'process.platform': '"browser"',
}),
].concat(isDev ? [new webpack.HotModuleReplacementPlugin()] : []),
resolve: {
extensions: ['.js', '.ts', '.tsx'],
alias: {
'react-dom': '@hot-loader/react-dom',
'@': path.resolve(__dirname, 'resources/assets/src'),
readline: '@/scripts/cli/readline.ts',
prompts: 'prompts/lib/index.js',
assert: false,
},
) as Record<string, string>,
optimization: {
minimizer: [new TerserJSPlugin({}), new CssMinimizerPlugin({})],
},
devtool: devMode ? 'cheap-module-eval-source-map' : false,
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
externals: Object.assign(
{ jquery: 'jQuery', bootstrap: 'bootstrap', 'admin-lte': 'adminlte' },
isDev
? {}
: {
react: 'React',
'react-dom': 'ReactDOM',
},
) as Record<string, string>,
optimization: {
// @ts-ignore
minimizer: [new CssMinimizerPlugin({}), '...'],
},
experiments: {
syncWebAssembly: true,
},
devtool: isDev ? 'eval-source-map' : false,
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
host: '0.0.0.0',
hot: true,
hotOnly: true,
stats: 'errors-only',
},
stats: 'errors-only',
},
host: '0.0.0.0',
hot: true,
hotOnly: true,
stats: 'errors-only',
},
stats: 'errors-only',
node: {
child_process: 'empty',
fs: 'empty',
},
{
name: 'meta',
mode: isDev ? 'development' : 'production',
entry: {
meta: './resources/assets/src/scripts/meta.ts',
sw: './resources/assets/src/scripts/sw.ts',
},
output: {
path: `${__dirname}/public`,
filename: '[name].js',
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: 'tsconfig.build.json',
transpileOnly: true,
},
},
],
},
plugins: [new SyncMetaJsPlugin()],
resolve: {
extensions: ['.js', '.ts'],
},
stats: 'errors-only',
},
]
}
if (devMode) {
config.plugins!.push(new webpack.NamedModulesPlugin())
config.plugins!.push(new webpack.HotModuleReplacementPlugin())
}
export default config

View File

@ -1,33 +0,0 @@
import * as webpack from 'webpack'
const devMode = !process.argv.includes('-p')
const config: webpack.Configuration = {
mode: devMode ? 'development' : 'production',
entry: {
meta: './resources/assets/src/scripts/meta.ts',
sw: './resources/assets/src/scripts/sw.ts',
},
output: {
path: `${__dirname}/public`,
filename: '[name].js',
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: 'tsconfig.build.json',
transpileOnly: true,
},
},
],
},
resolve: {
extensions: ['.js', '.ts', '.tsx', '.json'],
},
stats: 'errors-only',
}
export default config

1497
yarn.lock

File diff suppressed because it is too large Load Diff