All files / tasks browserSync.ts

93.02% Statements 40/43
94.74% Branches 36/38
75% Functions 3/4
92.86% Lines 39/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 1321x 1x 1x 1x 1x 1x                     6x 6x   1x 1x 1x     5x 5x 5x     1x       3x                       3x 3x           5x   5x   5x 5x                     3x 3x 3x 3x 3x     3x       3x     3x                                                             5x 5x       4x 4x   2x 5x     4x     5x 5x    
import * as MBrowserSync from 'browser-sync'
import chalk from 'chalk'
import * as log from 'fancy-log'
import * as os from 'os'
import * as webpack from 'webpack'
import {
  devLogger,
  devLoggerTitle,
  ITimplaTask,
  projectPath,
  setDisplayName,
  sureLazyImport,
  TIMPLA_PROCESS as TP,
  webpackMultiConfig,
} from '../internal'
 
export const browserSync: ITimplaTask = timplaConfig => cb => {
  const browserSyncConfig = timplaConfig.browserSync
  if (!browserSyncConfig) {
    log(chalk.yellow('========= Browsersync disabled ========='))
    cb()
    return
  }
 
  const devConfig = timplaConfig.development
  const middlewareConfig = devConfig.middlewareConfig
  const proxyConfig = browserSyncConfig.proxy || null
 
  if (typeof proxyConfig === 'string') {
    browserSyncConfig.proxy = {
      target: proxyConfig,
    }
  } else if (!proxyConfig && !browserSyncConfig.server && !devConfig.disableServerFallback) {
    browserSyncConfig.server = {
      baseDir: timplaConfig.dest,
    }
  }
 
  // Resolve path from project
  if (
    browserSyncConfig.server &&
    typeof browserSyncConfig.server === 'object' &&
    !(browserSyncConfig.server instanceof Array) &&
    browserSyncConfig.server.baseDir
  ) {
    const baseDir = browserSyncConfig.server.baseDir
    browserSyncConfig.server.baseDir = Array.isArray(baseDir)
      ? baseDir.map(e => projectPath(e))
      : projectPath(baseDir)
  }
 
  // Override open with TIMPLA_RELOAD check so as not to annoy dev mode users!
  browserSyncConfig.open = !TP.isTimplaReloaded && browserSyncConfig.open
 
  const server: MBrowserSync.ServerOptions = (browserSyncConfig.proxy ||
    browserSyncConfig.server) as MBrowserSync.ServerOptions
  const prepMiddleware: any[] = []
  const isCustomisable = typeof server === 'object' && !(server instanceof Array)
 
  // can be a choke point when logging, so let's clear it first...
  // we'll re-set this after we log the config
  if (server && server.middleware) {
    prepMiddleware.push(...server.middleware)
    delete server.middleware
  }
 
  // Enhance middleware
  if (isCustomisable && middlewareConfig) {
    const webpackConfig = webpackMultiConfig(timplaConfig)('development')
    const compiler = webpack(webpackConfig)
    const webpackDevMiddleware = sureLazyImport('webpack-dev-middleware')
    const webpackHotMiddleware = sureLazyImport('webpack-hot-middleware')
    const historyApiFallback = sureLazyImport('connect-history-api-fallback')
 
    // Two ways to disable the SPA middleware
    const enableSpa = !!middlewareConfig.connectHistoryApiFallbackMiddleware && !proxyConfig
 
    // Two ways to disable HMR
    const enableWebpackHotMiddleware =
      !!middlewareConfig.webpackHotMiddleware && !!devConfig.webpackHotMiddlewareClient
 
    // Add config-controlled middleware
    prepMiddleware.push(
      ...[
        middlewareConfig.webpackDevMiddleware &&
          setDisplayName(
            webpackDevMiddleware(compiler, {
              publicPath: webpackConfig.output.publicPath,
              watchOptions: browserSyncConfig.watchOptions || {},
              ...middlewareConfig.webpackDevMiddleware,
            }),
            'webpack-dev-middleware'
          ),
        enableWebpackHotMiddleware &&
          setDisplayName(
            webpackHotMiddleware(compiler, {
              log: false,
              ...middlewareConfig.webpackHotMiddleware,
            }),
            'webpack-hot-middleware'
          ),
        // Useful for developing spas
        // Redirects requests to root index.html if no corresponding files are found
        enableSpa &&
          setDisplayName(
            historyApiFallback(middlewareConfig.connectHistoryApiFallbackMiddleware),
            'connect-history-api-fallback'
          ),
      ].filter(Boolean)
    )
  }
 
  // User should be informed of the modified browsersyncConfig
  devLoggerTitle('BrowserSync config')
  devLogger('%O', browserSyncConfig)
 
  // Switch server with cloned since we're done logging
  if (server) {
    server.middleware = prepMiddleware
    let middlewareMessage = 'No middleware used!'
    if (Array.isArray(server.middleware) && server.middleware.length) {
      middlewareMessage = server.middleware
        .map((e: any) => e.displayName || e.constructor.name || e.name)
        .join(', ')
    }
    devLogger('middleware', chalk.magenta(middlewareMessage), os.EOL)
  }
 
  MBrowserSync.init(browserSyncConfig)
  cb()
}