vite#ViteDevServer TypeScript Examples

The following examples show how to use vite#ViteDevServer. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: server.ts    From vite-ssr with MIT License 6 votes vote down vote up
export function printServerInfo(server: ViteDevServer) {
  const info = server.config.logger.info

  let ssrReadyMessage = '\n -- SSR mode'

  if (Object.prototype.hasOwnProperty.call(server, 'printUrls')) {
    info(
      chalk.cyan(`\n  vite v${require('vite/package.json').version}`) +
        chalk.green(` dev server running at:\n`),
      { clear: !server.config.logger.hasWarned }
    )

    // @ts-ignore
    server.printUrls()

    // @ts-ignore
    if (globalThis.__ssr_start_time) {
      ssrReadyMessage += chalk.cyan(
        ` ready in ${Math.round(
          // @ts-ignore
          performance.now() - globalThis.__ssr_start_time
        )}ms.`
      )
    }
  }

  info(ssrReadyMessage + '\n')
}
Example #2
Source File: handleError.ts    From telefunc with MIT License 6 votes vote down vote up
function handleError(err: unknown, viteDevServer: ViteDevServer | null) {
  // We ensure we print a string; Cloudflare Workers doesn't seem to properly stringify `Error` objects.
  const errStr = (hasProp(err, 'stack') && String(err.stack)) || String(err)

  if (viteAlreadyLoggedError(err, viteDevServer)) {
    return
  }
  viteErrorCleanup(err, viteDevServer)

  console.error(errStr)
}
Example #3
Source File: handleError.ts    From telefunc with MIT License 6 votes vote down vote up
function viteErrorCleanup(err: unknown, viteDevServer: ViteDevServer | null) {
  if (!viteDevServer) {
    return false
  }
  if (hasProp(err, 'stack')) {
    // Apply source maps
    viteDevServer.ssrFixStacktrace(err as Error)
  }
}
Example #4
Source File: loadTelefuncFiles.ts    From telefunc with MIT License 6 votes vote down vote up
async function loadTelefuncFiles(runContext: {
  root: string | null
  viteDevServer: ViteDevServer | null
  isProduction: boolean
  telefuncFiles: string[] | null
}): Promise<TelefuncFiles | null> {
  // Handles:
  // - When the user provides the telefunc file paths with `telefuncConfig.telefuncFiles`
  if (runContext.telefuncFiles) {
    const telefuncFilesLoaded = loadTelefuncFilesFromConfig(runContext.telefuncFiles, runContext.root)
    return telefuncFilesLoaded
  }

  // Handles:
  // - Next.js
  // - Nuxt
  // - Vite with `importBuild.js`
  {
    const telefuncFilesLoaded = loadTelefuncFilesWithInternalMechanism()
    if (telefuncFilesLoaded) {
      assertUsage(Object.keys(telefuncFilesLoaded).length > 0, getErrMsg('webpack'))
      return telefuncFilesLoaded
    }
  }

  // Handles:
  // - Vite
  {
    const { telefuncFilesLoaded, viteProvider } = await loadTelefuncFilesWithVite(runContext)
    if (telefuncFilesLoaded) {
      assertUsage(Object.keys(telefuncFilesLoaded).length > 0, getErrMsg(`Vite [\`${viteProvider}\`]`))
      return telefuncFilesLoaded
    }
  }

  assertUsage(false, "You don't seem to be using Telefunc with a supported stack. Reach out on GitHub or Discord.")
}
Example #5
Source File: loadTelefuncFilesWithVite.ts    From telefunc with MIT License 6 votes vote down vote up
async function loadTelefuncFilesWithVite(runContext: {
  root: string | null
  viteDevServer: ViteDevServer | null
  isProduction: boolean
}) {
  const { notFound, moduleExports, provider } = await loadGlobImporter(runContext)

  if (notFound) {
    return { telefuncFilesLoaded: null }
  }

  // console.log('provider', provider)
  assert(isObject(moduleExports), { moduleExports, provider })
  assert(hasProp(moduleExports, 'telefuncFilesGlob'), { moduleExports, provider })
  const telefuncFilesGlob = moduleExports.telefuncFilesGlob as GlobFiles
  const telefuncFilesLoaded = await loadGlobFiles(telefuncFilesGlob)
  assert(isObjectOfObjects(telefuncFilesLoaded))
  return { telefuncFilesLoaded, viteProvider: provider }
}
Example #6
Source File: handleError.ts    From telefunc with MIT License 5 votes vote down vote up
function viteAlreadyLoggedError(err: unknown, viteDevServer: ViteDevServer | null) {
  if (!viteDevServer) {
    return false
  }
  return viteDevServer.config.logger.hasErrorLogged(err as Error)
}
Example #7
Source File: telefuncConfig.ts    From telefunc with MIT License 5 votes vote down vote up
configSpec = {
  isProduction: {
    validate(val: unknown) {
      assertUsage(val === true || val === false, '`telefuncConfig.isProduction` should be `true` or `false`')
    },
    getDefault() {
      // If server environment is not a Node.js server, then we assume a (Cloudflare) worker environment
      if (typeof process == 'undefined' || !hasProp(process, 'env')) return true
      return process.env.NODE_ENV === 'production'
    }
  },
  root: {
    validate(val: unknown) {
      assertUsage(typeof val === 'string' && isAbsolute(val), '`telefuncConfig.root` should be an absolute path')
    },
    getDefault() {
      if (typeof process == 'undefined' || !hasProp(process, 'cwd')) return null
      return process.cwd()
    }
  },
  viteDevServer: {
    validate(val: unknown) {
      assertInfo(
        false,
        '`telefuncConfig.viteDevServer` is not needed anymore. Remove your `telefuncConfig.viteDevServer` configuration to get rid of this message. (Telefunc now automatically retrieves the Vite dev server.)'
      )
      assertUsage(hasProp(val, 'ssrLoadModule'), '`telefuncConfig.ssrLoadModule` should be the Vite dev server')
      assertUsage(
        (val as any as ViteDevServer).config.plugins.find((plugin) => plugin.name.startsWith('telefunc')),
        'Telefunc Vite plugin not installed. Make sure to add Telefunc to your `vite.config.js`.'
      )
      assert(val === globalContext.viteDevServer, '`viteDevServer` mismatch.')
    },
    getDefault() {
      return null
    }
  },
  telefuncUrl: {
    validate(val: unknown) {
      assertUsage(
        typeof val === 'string' && val.startsWith('/'),
        '`telefuncConfig.telefuncUrl` should be a string that starts with `/`'
      )
    },
    getDefault() {
      return '/_telefunc'
    }
  },
  telefuncFiles: {
    validate(val: unknown) {
      assertWarning(false, '`telefuncConfig.telefuncFiles` is experimental', { onlyOnce: true })
      assertUsage(
        Array.isArray(val) && val.every((v) => typeof v === 'string' && isAbsolute(v)),
        '`telefuncConfig.telefuncFiles` should be a list of absolute paths'
      )
    },
    getDefault() {
      return null
    }
  },
  disableEtag: {
    validate(_val: unknown) {
      assertWarning(false, '`telefuncConfig.disableEtag` is experimental', { onlyOnce: true })
    },
    getDefault() {
      return false
    }
  },
  debug: {
    validate(val: unknown) {
      assertUsage(typeof val === 'boolean', '`telefuncConfig.debug` should be a boolean')
    },
    getDefault() {
      if (typeof process == 'undefined' || !hasProp(process, 'env')) return false
      return !!process.env.DEBUG
    }
  }
}
Example #8
Source File: loadTelefuncFilesWithVite.ts    From telefunc with MIT License 5 votes vote down vote up
async function loadGlobImporter(runContext: {
  root: string | null
  viteDevServer: ViteDevServer | null
  isProduction: boolean
}) {
  if (runContext.viteDevServer) {
    const devPath = telefuncFilesGlobFilePath
    let moduleExports: unknown
    try {
      moduleExports = await runContext.viteDevServer.ssrLoadModule(devPath)
    } catch (err: unknown) {
      runContext.viteDevServer.ssrFixStacktrace(err as Error)
      throw err
    }
    return { moduleExports, provider: 'DEV_SERVER' as const }
  }

  /*
  {
    let moduleExports: unknown | null = null
    try {
      moduleExports = await import('./telefuncFilesGlob')
    } catch (_) {}
    if (moduleExports !== null) {
      assert(!hasProp(moduleExports, 'importGlobUnset'))
      return { moduleExports, provider: 'DIRECT' as const }
    }
  }
  */

  {
    const moduleExports: unknown = await import('./telefuncFilesGlobFromDist')
    if (!hasProp(moduleExports, 'distLinkUnset', 'true')) {
      assert(hasProp(moduleExports, 'distLinkActivated', 'boolean'))
      if (moduleExports.distLinkActivated === true) {
        assertProd(runContext)
        return { moduleExports, provider: 'DIST_LINK' as const }
      }
    }
  }

  if (runContext.root) {
    const userDist = `${runContext.root}/dist`
    const prodPath = `${userDist}/server/${telefuncFilesGlobFileNameBase}.js`
    const prodPathResolved = resolve(prodPath)
    if (moduleExists(prodPathResolved)) {
      const moduleExports: unknown = nodeRequire(prodPathResolved)
      assertProd(runContext)
      return { moduleExports, provider: 'NODE_JS' as const }
    }
  }

  return { notFound: true }
}
Example #9
Source File: createPageRenderer.ts    From vite-plugin-ssr with MIT License 4 votes vote down vote up
function assertArguments(
  ssrEnv: {
    viteDevServer?: unknown
    root?: unknown
    outDir?: unknown
    isProduction?: unknown
    baseUrl?: unknown
    baseAssets?: unknown
  },
  args: unknown[],
): asserts ssrEnv is SsrEnv {
  const { viteDevServer, root, outDir, isProduction, baseUrl, baseAssets } = ssrEnv
  assertUsage(
    root === undefined || typeof root === 'string',
    '`createPageRenderer({ root })`: argument `root` should be a string.',
  )
  assertUsage(typeof outDir === 'string', '`createPageRenderer({ outDir })`: argument `outDir` should be a string.')
  assertUsage(typeof baseUrl === 'string', '`createPageRenderer({ base })`: argument `base` should be a string.')
  assertUsage(
    baseAssets === null || typeof baseAssets === 'string',
    '`createPageRenderer({ baseAssets })`: argument `baseAssets` should be a string.',
  )
  assertUsageBaseUrl(baseUrl, '`createPageRenderer({ base })`: ')
  assertUsage(
    isProduction === true || isProduction === false || isProduction === undefined,
    '`createPageRenderer({ isProduction })`: argument `isProduction` should be `true`, `false`, or `undefined`.',
  )
  if (importBuildWasLoaded()) {
    assertUsage(
      isProduction,
      '`createPageRenderer({ isProduction })`: argument `isProduction` should be `true` if `dist/server/importBuild.js` is loaded. (You should load `dist/server/importBuild.js` only in production.)',
    )
    assertUsage(
      root === undefined,
      '`createPageRenderer({ root })`: argument `root` has no effect if `dist/server/importBuild.js` is loaded. Remove the `root` argument.',
    )
  }
  if (isProduction === true) {
    assertUsage(
      viteDevServer === undefined,
      '`createPageRenderer({ viteDevServer, isProduction })`: if `isProduction` is `true`, then `viteDevServer` should be `undefined`.',
    )
    assertUsage(
      root || importBuildWasLoaded(),
      "`createPageRenderer({ root })`: argument `root` is missing. (Alternatively, if `root` doesn't exist because you are bundling your server code into a single file, then load `dist/server/importBuild.js`.)",
    )
  } else {
    assertUsage(root, '`createPageRenderer({ root })`: argument `root` is missing.')

    assertUsage(
      !!viteDevServer,
      '`createPageRenderer({ viteDevServer, isProduction })`: if `isProduction` is not `true`, then `viteDevServer` cannot be `undefined`.',
    )

    const wrongViteDevServerValueError =
      '`createPageRenderer({ viteDevServer, isProduction })`: if `isProduction` is not `true`, then `viteDevServer` should be `viteDevServer = await vite.createServer(/*...*/)`.'
    assertUsage(
      hasProp(viteDevServer, 'config') &&
        hasProp(viteDevServer.config, 'root') &&
        typeof viteDevServer.config.root === 'string',
      wrongViteDevServerValueError,
    )
    {
      const rootVite = resolve(viteDevServer.config.root)
      const rootResolved = resolve(root)
      assertUsage(
        rootVite === rootResolved,
        '`createPageRenderer({ viteDevServer, root })`: wrong `root` value, make sure it matches `viteDevServer.config.root`. ' +
          `The \`root\` you provided resolves to \`'${rootResolved}'\` while \`viteDevServer.config.root\` resolves to \`${rootVite}\`.`,
      )
    }

    assertUsage(
      hasProp(viteDevServer, 'config', 'object') && hasProp(viteDevServer.config, 'plugins', 'array'),
      wrongViteDevServerValueError,
    )
    assertUsage(
      (viteDevServer as any as ViteDevServer).config.plugins.find((plugin) =>
        plugin.name.startsWith('vite-plugin-ssr'),
      ),
      "`vite-plugin-ssr`'s Vite plugin is not installed. Make sure to add it to your `vite.config.js`.",
    )
  }
  assertUsage(args.length === 1, '`createPageRenderer()`: all arguments should be passed as a single argument object.')
  assert(typeof args[0] === 'object' && args[0] !== null)
  Object.keys(args[0]).forEach((argName) => {
    assertUsage(
      ['viteDevServer', 'root', 'outDir', 'isProduction', 'base', 'baseAssets'].includes(argName),
      '`createPageRenderer()`: Unknown argument `' + argName + '`.',
    )
  })
}
Example #10
Source File: vite.ts    From farrow with MIT License 4 votes vote down vote up
vite = (options?: FarrowViteOptions): ViteRouterPipeline => {
  const router = Router()

  const config = {
    ...options,
  }

  let viteDevServers: ViteDevServer[] = []

  router.useLazy(async () => {
    const viteServer = await createViteServer({
      server: {
        ...config.server,
        middlewareMode: true,
      },
      ...config,
    })

    const getHtmlPath = async (url: string): Promise<string> => {
      const pathname = url.split('?')[0]
      /**
       * pathname.slice(1) is to remove the first '/'
       * /dir/file.html => dir/file.html
       * path.join('/root', 'dir/file.html') => /root/dir/file.html
       */
      const filename = path.join(viteServer.config.root, pathname.slice(1))

      if (filename.endsWith('.html')) {
        return filename
      }

      const maybeHtmlPath = `${filename}/index.html`
      try {
        await fs.access(maybeHtmlPath, constants.R_OK)
        return `${filename}/index.html`
      } catch (error) {
        // if subfolder has no index.html found, use the root folder's instead
        return `${viteServer.config.root}/index.html`
      }
    }

    const handler: CustomBodyHandler = ({ req, res }) => {
      viteServer.middlewares(req, res, async () => {
        try {
          const url = req.url ?? '/'
          const htmlPath = await getHtmlPath(url)
          const fileContent = await fs.readFile(htmlPath, 'utf-8')
          const html = await viteServer.transformIndexHtml(url, fileContent)

          res.statusCode = 200
          res.setHeader('Content-Type', 'text/html')

          if (options?.onBeforeSendHtml) {
            res.end(await options.onBeforeSendHtml(html))
          } else {
            res.end(html)
          }
        } catch (error: any) {
          if (!res.headersSent) {
            res.setHeader('Content-Type', 'text/plain')
          }

          const message = process.env.NODE_ENV === 'production' ? error.message : error.stack ?? error.message

          res.statusCode = 500
          res.end(message ?? '')
        }
      })
    }

    viteDevServers.push(viteServer)

    return () => {
      return Response.custom(handler)
    }
  })

  return {
    ...router,
    async close() {
      const servers = [...viteDevServers]

      viteDevServers = []

      await Promise.all(servers.map((server) => server.close()))
    },
  }
}
Example #11
Source File: server.ts    From vite-ssr with MIT License 4 votes vote down vote up
createSSRDevHandler = (
  server: ViteDevServer,
  options: SsrOptions = {}
) => {
  options = {
    ...server.config.inlineConfig, // CLI flags
    ...options,
  }

  const pluginOptions = getPluginOptions(server.config)
  const resolve = (p: string) => path.resolve(server.config.root, p)
  async function getIndexTemplate(url: string) {
    // Template should be fresh in every request
    const indexHtml = await fs.readFile(
      pluginOptions.input || resolve('index.html'),
      'utf-8'
    )
    return await server.transformIndexHtml(url, indexHtml)
  }

  function writeHead(response: ServerResponse, params: WriteResponse = {}) {
    if (params.status) {
      response.statusCode = params.status
    }

    if (params.statusText) {
      response.statusMessage = params.statusText
    }

    if (params.headers) {
      for (const [key, value] of Object.entries(params.headers)) {
        response.setHeader(key, value)
      }
    }
  }

  const handleSsrRequest: NextHandleFunction = async (
    request,
    response,
    next
  ) => {
    if (request.method !== 'GET' || request.originalUrl === '/favicon.ico') {
      return next()
    }

    let template: string

    try {
      template = await getIndexTemplate(request.originalUrl as string)
    } catch (error) {
      server.ssrFixStacktrace(error as Error)
      return next(error)
    }

    try {
      const entryPoint =
        options.ssr || (await getEntryPoint(server.config, template))

      let resolvedEntryPoint = await server.ssrLoadModule(resolve(entryPoint))
      resolvedEntryPoint = resolvedEntryPoint.default || resolvedEntryPoint
      const render = resolvedEntryPoint.render || resolvedEntryPoint

      const protocol =
        // @ts-ignore
        request.protocol ||
        (request.headers.referer || '').split(':')[0] ||
        'http'

      const url = protocol + '://' + request.headers.host + request.originalUrl

      // This context might contain initialState provided by other plugins
      const context =
        (options.getRenderContext &&
          (await options.getRenderContext({
            url,
            request,
            response,
            resolvedEntryPoint,
          }))) ||
        {}

      // This is used by Vitedge
      writeHead(response, context)
      if (isRedirect(context)) {
        return response.end()
      }

      const result = await render(url, {
        request,
        response,
        template,
        ...context,
      })

      writeHead(response, result)
      if (isRedirect(result)) {
        return response.end()
      }

      response.setHeader('Content-Type', 'text/html')
      response.end(result.html)
    } catch (error) {
      // Send back template HTML to inject ViteErrorOverlay
      response.setHeader('Content-Type', 'text/html')
      response.end(template)

      // Wait until browser injects ViteErrorOverlay
      // custom element from the previous template
      setTimeout(() => next(error), 250)
      server.ssrFixStacktrace(error as Error)
    }
  }

  return handleSsrRequest
}
Example #12
Source File: index.ts    From vanilla-extract with MIT License 4 votes vote down vote up
export function vanillaExtractPlugin({ identifiers }: Options = {}): Plugin {
  let config: ResolvedConfig;
  let server: ViteDevServer;
  let postCssConfig: PostCSSConfigResult | null;
  const cssMap = new Map<string, string>();

  let virtualExt: string;
  let packageName: string;

  return {
    name: 'vanilla-extract',
    enforce: 'pre',
    configureServer(_server) {
      server = _server;
    },
    config(_userConfig, env) {
      const include =
        env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];

      return {
        optimizeDeps: { include },
        ssr: {
          external: [
            '@vanilla-extract/css',
            '@vanilla-extract/css/fileScope',
            '@vanilla-extract/css/adapter',
          ],
        },
      };
    },
    async configResolved(resolvedConfig) {
      config = resolvedConfig;
      packageName = getPackageInfo(config.root).name;

      if (config.command === 'serve') {
        postCssConfig = await resolvePostcssConfig(config);
      }

      virtualExt = `.vanilla.${config.command === 'serve' ? 'js' : 'css'}`;
    },
    resolveId(id) {
      if (!id.endsWith(virtualExt)) {
        return;
      }

      const normalizedId = id.startsWith('/') ? id.slice(1) : id;

      if (cssMap.has(normalizedId)) {
        return normalizePath(path.join(config.root, normalizedId));
      }
    },
    load(id) {
      if (!id.endsWith(virtualExt)) {
        return;
      }

      const cssFileId = id.slice(config.root.length + 1);
      const css = cssMap.get(cssFileId);

      if (typeof css !== 'string') {
        return;
      }

      if (!server) {
        return css;
      }

      return outdent`
        import { injectStyles } from '@vanilla-extract/css/injectStyles';
        
        const inject = (css) => injectStyles({
          fileScope: ${JSON.stringify({ filePath: cssFileId })},
          css
        });

        inject(${JSON.stringify(css)});

        import.meta.hot.on('${styleUpdateEvent(cssFileId)}', (css) => {
          inject(css);
        });   
      `;
    },
    async transform(code, id, ssrParam) {
      if (!cssFileFilter.test(id)) {
        return null;
      }

      let ssr: boolean | undefined;

      if (typeof ssrParam === 'boolean') {
        ssr = ssrParam;
      } else {
        ssr = ssrParam?.ssr;
      }

      const index = id.indexOf('?');
      const validId = index === -1 ? id : id.substring(0, index);

      if (ssr) {
        return addFileScope({
          source: code,
          filePath: normalizePath(validId),
          rootPath: config.root,
          packageName,
        });
      }

      const { source, watchFiles } = await compile({
        filePath: validId,
        cwd: config.root,
      });

      for (const file of watchFiles) {
        // In start mode, we need to prevent the file from rewatching itself.
        // If it's a `build --watch`, it needs to watch everything.
        if (config.command === 'build' || file !== id) {
          this.addWatchFile(file);
        }
      }

      const output = await processVanillaFile({
        source,
        filePath: validId,
        identOption:
          identifiers ?? (config.mode === 'production' ? 'short' : 'debug'),
        serializeVirtualCssPath: async ({ fileScope, source }) => {
          const id = `${fileScope.filePath}${virtualExt}`;

          let cssSource = source;

          if (postCssConfig) {
            const postCssResult = await (await import('postcss'))
              .default(postCssConfig.plugins)
              .process(source, {
                ...postCssConfig.options,
                from: undefined,
                map: false,
              });

            cssSource = postCssResult.css;
          }

          if (server && cssMap.has(id) && cssMap.get(id) !== source) {
            const { moduleGraph } = server;
            const moduleId = normalizePath(path.join(config.root, id));
            const module = moduleGraph.getModuleById(moduleId);

            if (module) {
              moduleGraph.invalidateModule(module);
            }

            server.ws.send({
              type: 'custom',
              event: styleUpdateEvent(id),
              data: cssSource,
            });
          }

          cssMap.set(id, cssSource);

          return `import "${id}";`;
        },
      });

      return {
        code: output,
        map: { mappings: '' },
      };
    },
  };
}