upgrade to webpack 5
Web CLI update: * commander -> cac * enquirer -> prompts
This commit is contained in:
parent
b07e227e91
commit
34c90b50f2
31
package.json
31
package.json
@ -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",
|
||||
|
@ -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}>
|
||||
×
|
||||
</button>
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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.")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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}"?`,
|
||||
|
@ -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')
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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
24
tools/SyncMetaJsPlugin.ts
Normal 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
|
@ -8,7 +8,8 @@
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./resources/assets/src/*"]
|
||||
}
|
||||
},
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": [
|
||||
"resources/assets/src",
|
||||
|
@ -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
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user