UNPKG

vite-plugin-browser-sync

Version:
307 lines (304 loc) 8.22 kB
import { bold, lightYellow, red } from "kolorist"; import process from "node:process"; import { create } from "browser-sync"; //#region src/server.ts const defaultPorts = { dev: 5173, preview: 4173, buildWatch: null }; /** * Hook browsersync server on vite */ var Server = class { constructor(obj) { this.logged = false; const { name, server, config, options, env } = obj; this.name = name; this.server = server; this.config = config; this.options = options; this.env = env; this.bsServer = create(this.name); if (typeof this.userBsOptions.logLevel === "undefined") this.logged = true; this.registerInit(); this.registerClose(); } /** * Get browser sync mode * @readonly */ get mode() { if (this.env === "preview") return "proxy"; let mode = this.userOptions && "mode" in this.userOptions && this.userOptions.mode ? this.userOptions.mode : "proxy"; if (this.userBsOptions.proxy) mode = "proxy"; return mode; } /** * Get browser sync instance * @readonly */ get bs() { return this.bsServer; } /** * Get vite server port * @readonly */ get port() { if (this.env === "buildWatch" || !this.server) return null; const defaultPort = defaultPorts[this.env]; return (this.env === "dev" ? this.config.server.port : this.config.preview.port) || defaultPort; } /** * Get user options * @readonly */ get userOptions() { return this.options && this.env in this.options ? this.options[this.env] : {}; } /** * Get user browsersync options * @readonly */ get userBsOptions() { return this.userOptions && this.userOptions.bs ? this.userOptions.bs : {}; } /** * Get Final browsersync options */ get bsOptions() { const bsOptions = this.userBsOptions; if (typeof bsOptions.logLevel === "undefined") bsOptions.logLevel = "silent"; if (typeof bsOptions.open !== "undefined") { if (this.env === "dev" && typeof this.config.server.open === "boolean") bsOptions.open = false; else if (this.env === "preview" && typeof this.config.preview.open === "boolean") bsOptions.open = false; } if (this.env === "dev" && typeof bsOptions.codeSync === "undefined") bsOptions.codeSync = false; if (this.mode === "snippet") { bsOptions.logSnippet = false; bsOptions.snippet = false; } bsOptions.online = bsOptions.online === true || this.server && typeof this.config.server.host !== "undefined" || false; if (this.env === "buildWatch") return bsOptions; if (this.mode === "proxy") { let target; if (this.server?.resolvedUrls?.local[0]) target = this.server?.resolvedUrls?.local[0]; else if (this.port) target = `${this.config.server.https ? "https" : "http"}://localhost:${this.port}/`; if (!bsOptions.proxy) bsOptions.proxy = { target, ws: true }; else if (typeof bsOptions.proxy === "string") bsOptions.proxy = { target: bsOptions.proxy, ws: true }; else if (typeof bsOptions.proxy === "object" && !bsOptions.proxy.ws) bsOptions.proxy.ws = true; } return bsOptions; } /** * Init browsersync server */ init() { return new Promise((resolve, reject) => { this.bsServer.init(this.bsOptions, (error, bs) => { if (error) { this.config.logger.error(red(`[vite-plugin-browser-sync] ${error.name} ${error.message}`), { error }); reject(error); } resolve(bs); }); }); } /* c8 ignore start */ /** * Log browsersync infos */ log() { const colorUrl = (url) => lightYellow(url.replace(/:(\d+)$/, (_, port) => `:${bold(port)}/`)); const urls = this.bsServer.getOption("urls").toJS(); const consoleTexts = { "local": "Local", "external": "External", "ui": "UI", "ui-external": "UI External", "tunnel": "Tunnel" }; for (const key in consoleTexts) if (Object.prototype.hasOwnProperty.call(consoleTexts, key)) { const text = consoleTexts[key]; if (Object.prototype.hasOwnProperty.call(urls, key)) this.config.logger.info(` ${lightYellow("➜")} ${bold(`BrowserSync - ${text}`)}: ${colorUrl(urls[key])}`); } } /** * Register log function on vite */ registerLog() { if (!this.logged) return; if (this.server && this.env === "dev") { let astroServer = false; try { astroServer = "pluginContainer" in this.server && this.server.environments.client.plugins.findIndex((plugin) => plugin.name === "astro:server") > -1; } catch {} if (astroServer) setTimeout(() => this.log(), 1e3); else { const _print = this.server.printUrls; this.server.printUrls = () => { _print(); this.log(); }; } } else this.log(); } /* c8 ignore stop */ /** * Register init */ async registerInit() { if (this.server && "listen" in this.server) { const _listen = this.server.listen; this.server.listen = async () => { const out = await _listen(); await this.init(); return out; }; } else if (this.server) { await new Promise((resolve) => { this.server?.httpServer?.once("listening", () => { resolve(true); }); }); await this.init(); } else await this.init(); this.registerLog(); } /** * Register close */ registerClose() { if (this.server) { const _close = this.server.close; this.server.close = async () => { this.bsServer.exit(); await _close(); }; this.server.httpServer?.on("close", () => { this.bsServer.exit(); }); } process.once("SIGINT", () => { this.bsServer.exit(); process.exit(); }); } }; //#endregion //#region src/index.ts /** * Vite plugin * * @example <caption>Basic Usage</caption> * ```ts * // vite.config.js / vite.config.ts * import VitePluginBrowserSync from 'vite-plugin-browser-sync' * * export default { * plugins: [VitePluginBrowserSync()] * } * ``` * @example <caption>With options</caption> * ```ts * // vite.config.js / vite.config.ts * import VitePluginBrowserSync from 'vite-plugin-browser-sync' * * export default { * plugins: [ * VitePluginBrowserSync({ * dev: { * bs: { * ui: { * port: 8080 * }, * notify: false * } * } * }) * ] * } * ``` */ function VitePluginBrowserSync(options) { const name = "vite-plugin-browser-sync"; const bsClientVersion = "3.0.4"; let config; let env = "dev"; let bsServer = null; let started = false; let applyOnDev = false; let applyOnPreview = false; let applyOnBuildWatch = false; return { name, apply(_config, env$1) { applyOnDev = env$1.command === "serve" && (typeof env$1.isPreview === "undefined" || env$1.isPreview === false) && options?.dev?.enable !== false; applyOnPreview = env$1.command === "serve" && env$1.isPreview === true && options?.preview?.enable === true; applyOnBuildWatch = env$1.command === "build" && (_config.build?.watch === true || typeof _config.build?.watch === "object") && options?.buildWatch?.enable === true; if (applyOnBuildWatch && options?.buildWatch?.mode !== "snippet" && typeof options?.buildWatch?.bs?.proxy !== "string" && typeof options?.buildWatch?.bs?.proxy?.target !== "string") { console.error(red("[vite-plugin-browser-sync] You need to set a browsersync target.")); return false; } return applyOnDev || applyOnPreview || applyOnBuildWatch; }, configResolved(_config) { config = _config; }, buildStart() { if (started || !applyOnBuildWatch) return; env = "buildWatch"; bsServer = new Server({ env, name, options, config }); started = true; }, async configureServer(server) { env = "dev"; bsServer = new Server({ env, name, server, options, config }); }, async configurePreviewServer(server) { env = "preview"; bsServer = new Server({ env, name, server, options, config }); }, transformIndexHtml: { order: "post", handler: (html) => { const applySnippet = applyOnDev || applyOnBuildWatch; if (!bsServer || bsServer.mode !== "snippet" || !applySnippet) return html; return [{ tag: "script", attrs: { async: "", src: `${bsServer.bs.getOption("urls").toJS().local}/browser-sync/browser-sync-client.js?v=${bsClientVersion}` }, injectTo: "body" }]; } } }; } //#endregion export { VitePluginBrowserSync as default };