vite-plugin-browser-sync
Version:
Add BrowserSync in your Vite project
330 lines (327 loc) • 9.84 kB
JavaScript
// src/index.ts
import { italic, red as red2 } from "kolorist";
// src/server.ts
import process2 from "node:process";
import { create } from "browser-sync";
import { bold, lightYellow, red } from "kolorist";
var defaultPorts = {
dev: 5173,
preview: 4173,
buildWatch: null
};
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];
const configPort = this.env === "dev" ? this.config.server.port : this.config.preview.port;
return configPort || 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() {
var _a, _b, _c, _d;
const bsOptions = this.userBsOptions;
if (typeof bsOptions.logLevel === "undefined")
bsOptions.logLevel = "silent";
if (this.server && typeof bsOptions.open === "undefined")
bsOptions.open = typeof this.config.server.open !== "undefined";
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 ((_b = (_a = this.server) == null ? void 0 : _a.resolvedUrls) == null ? void 0 : _b.local[0]) {
target = (_d = (_c = this.server) == null ? void 0 : _c.resolvedUrls) == null ? void 0 : _d.local[0];
} else if (this.port) {
const protocol = this.config.server.https ? "https" : "http";
target = `${protocol}://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("\u279C")} ${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 (e) {
astroServer = "pluginContainer" in this.server && this.server.pluginContainer.plugins.findIndex(
(plugin) => plugin.name === "astro:server"
) > -1;
}
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) => {
var _a, _b;
(_b = (_a = this.server) == null ? void 0 : _a.httpServer) == null ? void 0 : _b.once("listening", () => {
resolve(true);
});
});
await this.init();
} else {
await this.init();
}
this.registerLog();
}
/**
* Register close
*/
registerClose() {
var _a;
if (this.server) {
const _close = this.server.close;
this.server.close = async () => {
this.bsServer.exit();
await _close();
};
(_a = this.server.httpServer) == null ? void 0 : _a.on("close", () => {
this.bsServer.exit();
});
}
process2.once("SIGINT", () => {
this.bsServer.exit();
process2.exit();
});
}
};
// src/index.ts
function VitePluginBrowserSync(options) {
const name = "vite-plugin-browser-sync";
const bsClientVersion = "3.0.3";
let config;
let env = "dev";
let bsServer = null;
let started = false;
let applyOnDev = false;
let applyOnPreview = false;
let applyOnBuildWatch = false;
return {
name,
apply(_config, env2) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
if (options == null ? void 0 : options.bs) {
console.error(
red2(
`[vite-plugin-browser-sync] Since 3.0, you should wrap your ${italic("bs")} option inside a ${italic("dev")} object.`
)
);
return false;
}
applyOnDev = env2.command === "serve" && (typeof env2.isPreview === "undefined" || env2.isPreview === false) && ((_a = options == null ? void 0 : options.dev) == null ? void 0 : _a.enable) !== false;
applyOnPreview = env2.command === "serve" && env2.isPreview === true && ((_b = options == null ? void 0 : options.preview) == null ? void 0 : _b.enable) === true;
applyOnBuildWatch = env2.command === "build" && (((_c = _config.build) == null ? void 0 : _c.watch) === true || typeof ((_d = _config.build) == null ? void 0 : _d.watch) === "object") && ((_e = options == null ? void 0 : options.buildWatch) == null ? void 0 : _e.enable) === true;
if (applyOnBuildWatch && ((_f = options == null ? void 0 : options.buildWatch) == null ? void 0 : _f.mode) !== "snippet" && typeof ((_h = (_g = options == null ? void 0 : options.buildWatch) == null ? void 0 : _g.bs) == null ? void 0 : _h.proxy) !== "string" && typeof ((_k = (_j = (_i = options == null ? void 0 : options.buildWatch) == null ? void 0 : _i.bs) == null ? void 0 : _j.proxy) == null ? void 0 : _k.target) !== "string") {
console.error(
red2(
"[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;
const urls = bsServer.bs.getOption("urls").toJS();
const bsScript = {
tag: "script",
attrs: {
async: "",
src: `${urls.local}/browser-sync/browser-sync-client.js?v=${bsClientVersion}`
},
injectTo: "body"
};
return [bsScript];
}
}
};
}
export {
VitePluginBrowserSync as default
};