@kissflow/form-field-scripts
Version:
Scripts to serve, build, lint, test, etc. a Kissflow's custom form field project.
213 lines (195 loc) • 8.71 kB
JavaScript
import path from 'path'
import { clearScreen } from './helpers.js'
import { logSummary } from './helpers.js'
import { performOnetimeChecks, performRuntimeChecks } from './verifications.js'
import { fileURLToPath } from 'url'
import webpack from 'webpack'
import chalk from 'chalk'
import { logBoxenError, logBoxenWarning } from '../logBoxen.js'
import {
DEFAULT_EXPORT_NOT_FOUND_ERROR,
DEFAULT_EXPORT_NOT_REACT_COMPONENT_ERROR,
} from './errors.js'
import fs from 'fs'
const getAsciiArtText = () => {
const currentFileUrl = new URL(import.meta.url)
const currentFilePath = fileURLToPath(currentFileUrl) // Decodes %20 to space
const asciiArtPath = path.join(
path.dirname(currentFilePath),
'./assets',
'kf-logo-ascii-art.txt'
)
const asciiArtText = fs.readFileSync(asciiArtPath, 'utf8')
return asciiArtText
}
const getPostBuildInstruction = () => {
const currentFileUrl = new URL(import.meta.url)
const currentFilePath = fileURLToPath(currentFileUrl) // Decodes %20 to space
const asciiArtPath = path.join(
path.dirname(currentFilePath),
'./assets',
'post-build-messages.txt'
)
const asciiArtText = fs.readFileSync(asciiArtPath, 'utf8')
return asciiArtText
}
const banner = () => {
if (isDevMode) {
console.log(getAsciiArtText())
} else {
console.log(getPostBuildInstruction())
}
}
const isDevMode = process.env.npm_lifecycle_event === 'dev'
class FormFieldWebpackPlugin {
apply(compiler) {
const getRunHook = () => {
return compiler.hooks.beforeRun
}
const runHook = getRunHook()
runHook.tap(FormFieldWebpackPlugin.name, async (compiler, callback) => {
compiler.hooks.thisCompilation.tap(
FormFieldWebpackPlugin.name,
async (compilation) => {
try {
try {
await performOnetimeChecks()
} catch (err) {
const { title, description } = err
logBoxenError({ title, description })
process.exit(0)
}
await performRuntimeChecks()
} catch (err) {
// Check,
// DEFAULT_EXPORT_NOT_FOUND_ERROR.
// DEFAULT_EXPORT_NOT_REACT_COMPONENT_ERROR
if (
err instanceof DEFAULT_EXPORT_NOT_FOUND_ERROR ||
err instanceof
DEFAULT_EXPORT_NOT_REACT_COMPONENT_ERROR
) {
compilation.errors = []
const error = new webpack.WebpackError(
err.description
)
error.modulePath = err.modulePath
compilation.errors.push(error)
}
}
}
)
})
compiler.hooks.done.tap(FormFieldWebpackPlugin.name, (stats) => {
if (isDevMode) {
clearScreen()
console.log()
} else {
console.log()
}
if (stats.hasErrors() || stats.hasWarnings()) {
let numberOfErrors = stats.compilation.errors.length
let numberOfWarnings = stats.compilation.warnings.length
const getModulePath = (error) => {
if (error?.module && error?.module?.resource) {
path.relative(
compiler?.context,
error?.module?.resource
)
} else if (error.modulePath) {
return error.modulePath
} else {
return 'Unknown file'
}
}
if (stats.hasWarnings()) {
stats.compilation.warnings.forEach((warning, index) => {
// The author of eslint webpack plugin is aggregating all the
// errors/warning associated with eslint and pushing it as a single
// item (compilation.errors.push(errors)), instead of pushing them one
// by one (compilation.errors.push(...errors)).
const { name } = warning
if (name === 'ESLintError') {
let warnings
if (warning.message.startsWith('[eslint]')) {
warnings = JSON.parse(
warning.message.slice('[eslint]'.length)
)
} else {
warnings = JSON.parse(warning.message)
}
numberOfWarnings--
for (const warning of warnings) {
const { messages, filePath } = warning
logBoxenWarning({
title: filePath,
description: messages.reduce(
(messages, message) => {
const { pos, ruleId } = message
numberOfWarnings++ // breaking the rules of func programming, but this works.
messages += `${chalk.bold('Line ' + pos)}: ${message.message} - ${chalk.yellow(ruleId)}\n`
return messages
},
''
),
})
}
} else {
numberOfWarnings--
}
})
}
if (stats.hasErrors()) {
const errors = stats.compilation.errors
errors.forEach((error) => {
const { name } = error
if (name === 'ESLintError') {
let errors
if (error.message.startsWith('[eslint]')) {
errors = JSON.parse(
error.message.slice('[eslint]'.length)
)
} else {
errors = JSON.parse(error.message)
}
numberOfErrors--
for (const error of errors) {
const { messages, filePath } = error
logBoxenError({
title: filePath,
description: messages.reduce(
(messages, message) => {
const { pos, ruleId } = message
numberOfErrors++ // this is not good (not functional programming), but still...
messages += `${chalk.bold('Line ' + pos)}: ${message.message} - ${chalk.red(ruleId)}\n`
return messages
},
''
),
})
}
} else {
const file = getModulePath(error)
const errorMsg = error.message ?? error
logBoxenError({
title: file,
description: errorMsg,
})
}
})
}
logSummary({ numberOfWarnings, numberOfErrors })
if (numberOfErrors <= 0) {
console.log()
banner()
}
} else {
banner()
}
})
compiler.hooks.failed.tap(FormFieldWebpackPlugin.name, (error) => {
console.error('Build failed with error:', error)
})
}
}
export default FormFieldWebpackPlugin