import path from 'path' ; import { compact } from 'lodash' ; import { Configuration } from 'webpack' ; import { Configuration as DevServerConfiguration } from 'webpack-dev-server' ; import FriendlyErrorsWebpackPlugin from '@soda/friendly-errors-webpack-plugin' ; import { merge } from 'webpack-merge' ; import launchInEditor from 'launch-editor-middleware' ; import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin' ; import { createHTMLPluginInstances , BuildContext } from '@reskript/config-webpack' ; import { BuildEntry , warnAndExitOnInvalidFinalizeReturn } from '@reskript/settings' ; import ProgressBarPlugin from './ProgressBarPlugin' ; import { addHotModuleToEntry , constructProxyConfiguration } from './utils' ; const getDevServerMessages = ( host , port , https , openPage = '' ) : string [ ] => [ `Your application is running here: ${ https ? 'https' : 'http' }://${ host }:${ port }/${ openPage }` , ] ; export const createWebpackDevServerPartial = async ( context , host = 'localhost' ) => { const { cwd , projectSettings : { devServer : { hot , port , openPage , https } } } = context ; const htmlPlugins = createHTMLPluginInstances ( { ... context , isDefaultTarget : true } ) ; const messageOptions = { compilationSuccessInfo : { messages : getDevServerMessages ( host , port , ! ! https ?. client , openPage ) , notes : [ ] , } , } ; const plugins = [ ... htmlPlugins , new FriendlyErrorsWebpackPlugin ( messageOptions ) as any , hot && new ReactRefreshWebpackPlugin ( { overlay : false , forceEnable : true } ) , new ProgressBarPlugin ( ) , ] ; const configuration = { output : { path : path . join ( cwd , 'dist' ) , publicPath : '/assets/' , filename : '[name].[contenthash].js' , } , plugins : compact ( plugins ) , } ; return configuration ; } ; interface Options { targetEntry : string ; proxyDomain ? : string ; extra ? : DevServerConfiguration ; } export const createWebpackDevServerConfig = async ( buildEntry , options ) => { const { targetEntry , proxyDomain , extra = { } } = options ; const { apiPrefixes , defaultProxyDomain , proxyRewrite , https , port , hot , } = buildEntry . projectSettings . devServer ; const proxyOptions = { https : https ?. proxy ?? false , prefixes : apiPrefixes , rewrite : proxyRewrite , targetDomain : proxyDomain || defaultProxyDomain , } ; const baseConfig = { port , proxy : constructProxyConfiguration ( proxyOptions ) , allowedHosts : 'all' , host : '0.0.0.0' , hot : hot ? 'only' : false , client : { overlay : { errors : true , warnings : false , } , } , devMiddleware : { publicPath : '/assets/' , stats : 'none' , } , headers : { 'Access-Control-Allow-Origin' : '*' , 'Access-Control-Allow-Methods' : 'GET, POST, PUT, DELETE, PATCH, OPTIONS' , 'Access-Control-Allow-Headers' : 'X-Requested-With, Content-Type, Authorization' , } , static : { watch : { ignored : /node_modules/ , } , } , historyApiFallback : { index : `/assets/${ targetEntry }.html` , disableDotRule : true , } , server : { type : https ?. client ? 'https' : 'http' , options : https ?. client ? https . serverOptions : undefined , } , setupMiddlewares : middlewares => { middlewares . unshift ( { name : 'open-in-editor' , path : '/__open_in_editor__' , middleware : launchInEditor ( ) } ) ; return middlewares ; } , } ; const mergedConfig = merge ( { devServer : baseConfig } , { devServer : extra } ) ; const finalized = buildEntry . projectSettings . devServer . finalize ( mergedConfig . devServer , buildEntry ) ; warnAndExitOnInvalidFinalizeReturn ( finalized , 'devServer' ) ; return finalized ; } ; interface InjectOptions { config : Configuration ; devServerConfig : DevServerConfiguration ; entry : string ; resolveBase : string ; hot : boolean ; } export const injectDevElements = async ( options ) => { const { config , devServerConfig , entry , resolveBase , hot } = options ; const devServerInjected = { ... config , devServer : devServerConfig , infrastructureLogging : { level : 'none' , } , stats : 'errors-warnings' , } ; const entryInjected = hot && typeof config . entry === 'object' && ! Array . isArray ( config . entry ) ? { ... devServerInjected , entry : { [ entry ] : await addHotModuleToEntry ( config . entry [ entry ] , resolveBase ) , } , } : devServerInjected ; return entryInjected ; } ;