├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── changelog.js ├── examples ├── 404.js ├── basic │ └── run.js ├── callback.js ├── express.js ├── less.js ├── middleware.css.injection.js ├── notify-styles.js ├── options.snippetOptions.js ├── proxy.gzip.js ├── proxy.headers.js ├── proxy.localhost.js ├── proxy.middleware.js ├── proxy.middleware.multi.js ├── proxy.proxyRes.js ├── proxy.rewriteRules.advanced.js ├── proxy.rewriteRules.simple.js ├── proxy.secure.js ├── proxy.vhost.js ├── server.basedir.js ├── server.basedir.mulitple.js ├── server.default.js ├── server.gzip.js ├── server.http2.js ├── server.latency.js ├── server.middleware.js ├── server.middleware.multiple.js ├── server.proxy.js ├── server.secure.js ├── server.secure.pfx.js ├── server.watch.js └── snippet │ ├── index.html │ └── run.js ├── lerna.json ├── nx.json ├── package-lock.json ├── package.json ├── packages ├── browser-sync-client │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE-MIT │ ├── README.md │ ├── index.js │ ├── lib │ │ ├── browser.utils.ts │ │ ├── dom-effects.ts │ │ ├── dom-effects │ │ │ ├── link-replace.dom-effect.ts │ │ │ ├── prop-set.dom-effect.ts │ │ │ ├── set-scroll.dom-effect.ts │ │ │ ├── set-window-name.dom-effect.ts │ │ │ └── style-set.dom-effect.ts │ │ ├── effects.ts │ │ ├── effects │ │ │ ├── browser-reload.effect.ts │ │ │ ├── browser-set-location.effect.ts │ │ │ ├── file-reload.effect.ts │ │ │ ├── set-element-toggle-value.effect.ts │ │ │ ├── set-element-value.effect.ts │ │ │ ├── set-options.effect.ts │ │ │ ├── set-scroll.ts │ │ │ └── simulate-click.effect.ts │ │ ├── index.ts │ │ ├── listeners.ts │ │ ├── listeners │ │ │ ├── clicks.listener.ts │ │ │ ├── form-inputs.listener.ts │ │ │ ├── form-toggles.listener.ts │ │ │ └── scroll.listener.ts │ │ ├── log.ts │ │ ├── messages │ │ │ ├── BrowserLocation.ts │ │ │ ├── BrowserNotify.ts │ │ │ ├── BrowserReload.ts │ │ │ ├── ClickEvent.ts │ │ │ ├── Connection.ts │ │ │ ├── Disconnect.ts │ │ │ ├── FileReload.ts │ │ │ ├── FormToggleEvent.ts │ │ │ ├── KeyupEvent.ts │ │ │ ├── OptionsSet.ts │ │ │ └── ScrollEvent.ts │ │ ├── notify.ts │ │ ├── scroll-restore.ts │ │ ├── socket-messages.ts │ │ ├── socket.ts │ │ ├── types.ts │ │ ├── types │ │ │ ├── socket.ts │ │ │ └── types.d.ts │ │ ├── utils.ts │ │ └── vendor │ │ │ ├── Reloader.ts │ │ │ ├── Timer.ts │ │ │ └── logger.ts │ ├── package-lock.json │ ├── package.json │ ├── test │ │ ├── .jshintrc │ │ ├── client-new │ │ │ ├── bs.options.js │ │ │ ├── code-sync.js │ │ │ ├── emitter.js │ │ │ ├── ghostmode.click.js │ │ │ ├── ghostmode.forms.inputs.js │ │ │ ├── ghostmode.forms.js │ │ │ ├── ghostmode.forms.submit.js │ │ │ ├── ghostmode.forms.toggles.js │ │ │ ├── ghostmode.js │ │ │ ├── ghostmode.location.js │ │ │ ├── ghostmode.scroll.js │ │ │ ├── index.js │ │ │ ├── libs │ │ │ │ └── assert.js │ │ │ ├── notify.js │ │ │ ├── socket.js │ │ │ ├── stubs │ │ │ │ └── bs.js │ │ │ └── utils.js │ │ ├── fixtures │ │ │ ├── css │ │ │ │ └── style.css │ │ │ ├── forms.html │ │ │ ├── index-large.html │ │ │ ├── index-urls.html │ │ │ ├── index.html │ │ │ ├── inputs.html │ │ │ ├── less.html │ │ │ ├── links.html │ │ │ ├── proxy-headers.html │ │ │ ├── proxy-ip.html │ │ │ ├── proxy-vhost.html │ │ │ ├── sass.html │ │ │ └── scrolling.html │ │ ├── karma.conf.ci.js │ │ ├── karma.conf.js │ │ ├── middleware │ │ │ ├── file.js │ │ │ └── middleware.js │ │ └── test.conf.js │ ├── tsconfig.json │ └── webpack.config.js ├── browser-sync-ui │ ├── .editorconfig │ ├── .gitignore │ ├── .jshintrc │ ├── LICENSE │ ├── README.md │ ├── crossbow.yaml │ ├── example.stream.js │ ├── index.js │ ├── lib │ │ ├── UI.js │ │ ├── async-tasks.js │ │ ├── async.js │ │ ├── client-elements.js │ │ ├── client-js.js │ │ ├── config.js │ │ ├── directive-stripper.js │ │ ├── hooks.js │ │ ├── opts.js │ │ ├── plugins │ │ │ ├── connections │ │ │ │ ├── connections.client.js │ │ │ │ ├── connections.directive.html │ │ │ │ ├── connections.html │ │ │ │ ├── connections.plugin.js │ │ │ │ └── lib │ │ │ │ │ └── connections.js │ │ │ ├── help │ │ │ │ ├── help.client.js │ │ │ │ ├── help.directive.html │ │ │ │ ├── help.html │ │ │ │ └── help.plugin.js │ │ │ ├── history │ │ │ │ ├── history.client.js │ │ │ │ ├── history.directive.html │ │ │ │ ├── history.html │ │ │ │ ├── history.js │ │ │ │ └── history.plugin.js │ │ │ ├── network-throttle │ │ │ │ ├── network-throttle.client.js │ │ │ │ ├── network-throttle.directive.html │ │ │ │ ├── network-throttle.html │ │ │ │ ├── network-throttle.js │ │ │ │ ├── network-throttle.plugin.js │ │ │ │ ├── targets.js │ │ │ │ └── throttle-server.js │ │ │ ├── overview │ │ │ │ ├── overview.client.js │ │ │ │ ├── overview.html │ │ │ │ ├── overview.plugin.js │ │ │ │ ├── snippet-info.html │ │ │ │ └── url-info.html │ │ │ ├── plugins │ │ │ │ ├── plugins.client.js │ │ │ │ ├── plugins.html │ │ │ │ └── plugins.plugin.js │ │ │ ├── remote-debug │ │ │ │ ├── client-files.js │ │ │ │ ├── compression.html │ │ │ │ ├── compression.js │ │ │ │ ├── css │ │ │ │ │ ├── pesticide-depth.css │ │ │ │ │ ├── pesticide.css │ │ │ │ │ └── pesticide.min.css │ │ │ │ ├── latency │ │ │ │ │ ├── latency.client.js │ │ │ │ │ ├── latency.html │ │ │ │ │ └── latency.js │ │ │ │ ├── no-cache.html │ │ │ │ ├── no-cache.js │ │ │ │ ├── overlay-grid │ │ │ │ │ ├── css │ │ │ │ │ │ ├── grid-overlay-horizontal.css │ │ │ │ │ │ └── grid-overlay-vertical.css │ │ │ │ │ ├── js │ │ │ │ │ │ └── grid-overlay.js │ │ │ │ │ ├── overlay-grid.client.js │ │ │ │ │ ├── overlay-grid.html │ │ │ │ │ └── overlay-grid.js │ │ │ │ ├── remote-debug.client.js │ │ │ │ ├── remote-debug.html │ │ │ │ └── remote-debug.plugin.js │ │ │ └── sync-options │ │ │ │ ├── sync-options.client.js │ │ │ │ ├── sync-options.html │ │ │ │ └── sync-options.plugin.js │ │ ├── resolve-plugins.js │ │ ├── server.js │ │ ├── transform.options.js │ │ ├── transforms.js │ │ ├── urls.js │ │ └── utils.js │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── css │ │ │ ├── components.css │ │ │ ├── core.css │ │ │ ├── core.css.map │ │ │ ├── core.min.css │ │ │ └── core.min.css.map │ │ ├── favicon.ico │ │ ├── fonts │ │ │ └── source-sans │ │ │ │ ├── sourcesanspro-bold-webfont.eot │ │ │ │ ├── sourcesanspro-bold-webfont.svg │ │ │ │ ├── sourcesanspro-bold-webfont.ttf │ │ │ │ ├── sourcesanspro-bold-webfont.woff │ │ │ │ ├── sourcesanspro-bold-webfont.woff2 │ │ │ │ ├── sourcesanspro-it-webfont.eot │ │ │ │ ├── sourcesanspro-it-webfont.svg │ │ │ │ ├── sourcesanspro-it-webfont.ttf │ │ │ │ ├── sourcesanspro-it-webfont.woff │ │ │ │ ├── sourcesanspro-it-webfont.woff2 │ │ │ │ ├── sourcesanspro-regular-webfont.eot │ │ │ │ ├── sourcesanspro-regular-webfont.svg │ │ │ │ ├── sourcesanspro-regular-webfont.ttf │ │ │ │ ├── sourcesanspro-regular-webfont.woff │ │ │ │ └── sourcesanspro-regular-webfont.woff2 │ │ ├── img │ │ │ ├── favicon.ico │ │ │ ├── icons │ │ │ │ ├── icons.svg │ │ │ │ └── preview.html │ │ │ ├── logo.svg │ │ │ └── ps-bg.gif │ │ ├── index.html │ │ └── js │ │ │ └── app.js │ ├── src │ │ ├── crossbow │ │ │ ├── _config.yml │ │ │ ├── _includes │ │ │ │ ├── enable.disable.hbs │ │ │ │ ├── form.input.checkbox.hbs │ │ │ │ ├── form.input.text.hbs │ │ │ │ ├── header.hbs │ │ │ │ ├── icon.hbs │ │ │ │ └── nav.hbs │ │ │ ├── _layouts │ │ │ │ ├── components.hbs │ │ │ │ ├── main.hbs │ │ │ │ └── parent.hbs │ │ │ ├── components.hbs │ │ │ ├── components │ │ │ │ ├── button-bars.hbs │ │ │ │ ├── buttons.hbs │ │ │ │ ├── footer.hbs │ │ │ │ ├── forms.hbs │ │ │ │ ├── header.hbs │ │ │ │ ├── heading.hbs │ │ │ │ ├── help-content.hbs │ │ │ │ ├── lists.hbs │ │ │ │ ├── panels.hbs │ │ │ │ ├── switches.hbs │ │ │ │ └── type.hbs │ │ │ ├── content │ │ │ │ └── help.content.hbs │ │ │ ├── help.hbs │ │ │ ├── history.hbs │ │ │ ├── network-throttle.hbs │ │ │ ├── plugins.hbs │ │ │ ├── remote-debug.hbs │ │ │ ├── server-info-snippet.hbs │ │ │ ├── server-info.hbs │ │ │ └── sync-options.hbs │ │ ├── scripts │ │ │ ├── angular.js │ │ │ ├── app.js │ │ │ ├── directives.js │ │ │ ├── directives │ │ │ │ ├── icon.js │ │ │ │ ├── link-to.js │ │ │ │ ├── new-tab.js │ │ │ │ └── switch.js │ │ │ ├── editor.js │ │ │ ├── filters.js │ │ │ ├── main │ │ │ │ └── controller.js │ │ │ ├── module.js │ │ │ ├── modules │ │ │ │ ├── bsClients.js │ │ │ │ ├── bsDisconnect.js │ │ │ │ ├── bsHistory.js │ │ │ │ ├── bsNotify.js │ │ │ │ ├── bsSocket.js │ │ │ │ └── bsStore.js │ │ │ ├── services │ │ │ │ ├── Options.js │ │ │ │ └── Pages.js │ │ │ └── utils.js │ │ ├── scss │ │ │ ├── _vars.scss │ │ │ ├── components.scss │ │ │ ├── core.scss │ │ │ ├── modules │ │ │ │ ├── _mixins.scss │ │ │ │ └── _reset.scss │ │ │ ├── theme │ │ │ │ ├── _animations.scss │ │ │ │ ├── _base.scss │ │ │ │ ├── _buttons.scss │ │ │ │ ├── _cloak.scss │ │ │ │ ├── _code.scss │ │ │ │ ├── _custom-icons.scss │ │ │ │ ├── _disconnect.scss │ │ │ │ ├── _footer.scss │ │ │ │ ├── _forms.scss │ │ │ │ ├── _grid.scss │ │ │ │ ├── _header.scss │ │ │ │ ├── _headings.scss │ │ │ │ ├── _helpers.scss │ │ │ │ ├── _links.scss │ │ │ │ ├── _lists.scss │ │ │ │ ├── _main-content.scss │ │ │ │ ├── _misc.scss │ │ │ │ ├── _msgs.scss │ │ │ │ ├── _notifications.scss │ │ │ │ ├── _panel.scss │ │ │ │ ├── _paragraphs.scss │ │ │ │ ├── _section-nav.scss │ │ │ │ ├── _sidebar.scss │ │ │ │ ├── _spinner.scss │ │ │ │ ├── _state.scss │ │ │ │ ├── _svg.scss │ │ │ │ ├── _switch.scss │ │ │ │ └── _top-bar.scss │ │ │ └── vendor │ │ │ │ ├── _fonts.scss │ │ │ │ └── _normalize.scss │ │ ├── svg-template.tmpl │ │ └── svg │ │ │ ├── bin.svg │ │ │ ├── block.svg │ │ │ ├── book.svg │ │ │ ├── bug.svg │ │ │ ├── circle-delete.svg │ │ │ ├── circle-minus.svg │ │ │ ├── circle-ok.svg │ │ │ ├── circle-pause.svg │ │ │ ├── circle-play.svg │ │ │ ├── circle-plus.svg │ │ │ ├── code.svg │ │ │ ├── cog.svg │ │ │ ├── devices.svg │ │ │ ├── github.svg │ │ │ ├── globe.svg │ │ │ ├── help.svg │ │ │ ├── home.svg │ │ │ ├── imac.svg │ │ │ ├── jh.svg │ │ │ ├── list.svg │ │ │ ├── list2.svg │ │ │ ├── logo-word.svg │ │ │ ├── logo.svg │ │ │ ├── newtab.svg │ │ │ ├── pen.svg │ │ │ ├── pencil.svg │ │ │ ├── plug.svg │ │ │ ├── repeat.svg │ │ │ ├── square-add.svg │ │ │ ├── square-up.svg │ │ │ ├── sync-browser.svg │ │ │ ├── sync.svg │ │ │ ├── syncall.svg │ │ │ ├── target.svg │ │ │ ├── terminal.svg │ │ │ ├── time.svg │ │ │ ├── trash.svg │ │ │ ├── twitter.svg │ │ │ └── wifi.svg │ ├── static │ │ ├── components │ │ │ ├── button-bars.html │ │ │ ├── buttons.html │ │ │ ├── footer.html │ │ │ ├── forms.html │ │ │ ├── header.html │ │ │ ├── heading.html │ │ │ ├── help-content.html │ │ │ ├── lists.html │ │ │ ├── panels.html │ │ │ ├── switches.html │ │ │ └── type.html │ │ └── content │ │ │ └── help.content.html │ ├── tasks │ │ ├── crossbow.js │ │ └── icons.js │ ├── templates │ │ ├── config.item.tmpl │ │ ├── config.tmpl │ │ ├── directives │ │ │ └── bs-switch.html │ │ ├── inline.template.tmpl │ │ ├── plugin.item.tmpl │ │ └── plugin.tmpl │ ├── test │ │ ├── .jshintrc │ │ ├── client │ │ │ └── e2e │ │ │ │ ├── bs-init.js │ │ │ │ ├── config.js │ │ │ │ ├── e2e.plugins.js │ │ │ │ ├── e2e.server-info.js │ │ │ │ ├── e2e.sync-options.js │ │ │ │ ├── test-utils.js │ │ │ │ └── tests │ │ │ │ ├── history.js │ │ │ │ ├── history.newtabs.js │ │ │ │ ├── home.js │ │ │ │ ├── network-throttle.auto.js │ │ │ │ ├── network-throttle.js │ │ │ │ ├── network-throttle.manual.js │ │ │ │ ├── network-throttle.remove.js │ │ │ │ ├── plugins.inline.js │ │ │ │ ├── plugins.js │ │ │ │ └── remote-debug.js │ │ ├── fixtures │ │ │ ├── content.html │ │ │ ├── css │ │ │ │ ├── blog.css │ │ │ │ └── bootstrap.css │ │ │ ├── forms.html │ │ │ ├── index.html │ │ │ ├── plugin-multi-templates │ │ │ │ ├── index.plugin.js │ │ │ │ ├── package.json │ │ │ │ └── ui │ │ │ │ │ ├── client.js │ │ │ │ │ ├── client2.js │ │ │ │ │ ├── test.directive.html │ │ │ │ │ ├── test.html │ │ │ │ │ └── test.list.html │ │ │ ├── plugin-noui │ │ │ │ ├── index.plugin.js │ │ │ │ └── package.json │ │ │ ├── plugin │ │ │ │ ├── index.plugin.js │ │ │ │ ├── package.json │ │ │ │ └── ui │ │ │ │ │ ├── client.js │ │ │ │ │ ├── test.directive.html │ │ │ │ │ └── test.html │ │ │ └── scrolling.html │ │ ├── opts.server.json │ │ ├── protractor.sh │ │ └── server │ │ │ ├── history │ │ │ └── history.js │ │ │ ├── init.js │ │ │ ├── plugins.js │ │ │ ├── plugins.templates.js │ │ │ └── remote-debug │ │ │ ├── client.files.js │ │ │ ├── latency.js │ │ │ ├── no-cache.js │ │ │ ├── throttle.https.js │ │ │ └── throttle.js │ └── webpack.config.js └── browser-sync │ ├── .gitignore │ ├── .prettierignore │ ├── certs │ ├── browsersync.pfx │ ├── gen.sh │ ├── server.crt │ ├── server.csr │ └── server.key │ ├── cli-options │ ├── opts.init.json │ ├── opts.recipe.json │ ├── opts.reload.json │ └── opts.start.json │ ├── lib │ ├── args.js │ ├── async-tasks.js │ ├── async.js │ ├── bin.ts │ ├── browser-sync.js │ ├── cli │ │ ├── cli-info.js │ │ ├── cli-options.ts │ │ ├── command.init.js │ │ ├── command.recipe.js │ │ ├── command.reload.js │ │ ├── command.start.ts │ │ └── transforms │ │ │ ├── addCwdToWatchOptions.ts │ │ │ ├── addDefaultIgnorePatterns.ts │ │ │ ├── addToFilesOption.ts │ │ │ ├── appendServerDirectoryOption.ts │ │ │ ├── appendServerIndexOption.ts │ │ │ ├── copyCLIIgnoreToWatchOptions.ts │ │ │ ├── handleExtensionsOption.ts │ │ │ ├── handleFilesOption.ts │ │ │ ├── handleGhostModeOption.ts │ │ │ ├── handleHostOption.ts │ │ │ ├── handlePortsOption.ts │ │ │ ├── handleProxyOption.ts │ │ │ └── handleServerOption.ts │ ├── config.js │ ├── connect-utils.js │ ├── default-config.js │ ├── file-event-handler.js │ ├── file-utils.js │ ├── file-watcher.js │ ├── hooks.js │ ├── http-protocol.js │ ├── index.js │ ├── internal-events.js │ ├── lodash.custom.js │ ├── logger.js │ ├── options.ts │ ├── plugins.js │ ├── public │ │ ├── exit.js │ │ ├── init.ts │ │ ├── notify.js │ │ ├── pause.js │ │ ├── public-utils.js │ │ ├── reload.js │ │ ├── resume.js │ │ └── stream.js │ ├── server │ │ ├── index.js │ │ ├── proxy-server.js │ │ ├── proxy-utils.js │ │ ├── serve-static-wrapper.ts │ │ ├── snippet-server.js │ │ ├── static-server.js │ │ └── utils.js │ ├── snippet.js │ ├── sockets.ts │ ├── tunnel.js │ ├── types.ts │ └── utils.ts │ ├── lodash.custom.min.js │ ├── package-lock.json │ ├── package.json │ ├── readme.md │ ├── templates │ ├── cli-template.js │ ├── connector.tmpl │ ├── script-tags-simple.html │ └── script-tags.html │ ├── test │ ├── env.js │ ├── fixtures │ │ ├── .tmp │ │ │ └── temp.css │ │ ├── alt │ │ │ └── index.htm │ │ ├── assets │ │ │ ├── import.css │ │ │ ├── import2.css │ │ │ ├── print.css │ │ │ └── style.css │ │ ├── base.html │ │ ├── bootstrap.html │ │ ├── bootstrap │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap.css │ │ │ │ └── justified-nav.css │ │ │ ├── index.html │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.js │ │ │ │ └── jquery-3.2.1.slim.min.js │ │ ├── bower.html │ │ ├── bower_components │ │ │ └── app.css │ │ ├── config │ │ │ ├── config.js │ │ │ ├── si-config-partial.js │ │ │ ├── si-config-ports.js │ │ │ ├── si-config-proxy.js │ │ │ ├── si-config.js │ │ │ └── si-default-config.js │ │ ├── css │ │ │ ├── bootstrap-less.css │ │ │ ├── bootstrap-scss.css │ │ │ └── bootstrap.css │ │ ├── fonts │ │ │ └── roboto │ │ │ │ ├── Roboto-Regular-demo.html │ │ │ │ ├── Roboto-Regular-webfont.eot │ │ │ │ ├── Roboto-Regular-webfont.svg │ │ │ │ ├── Roboto-Regular-webfont.ttf │ │ │ │ ├── Roboto-Regular-webfont.woff │ │ │ │ └── stylesheet.css │ │ ├── forms.html │ │ ├── iframe.html │ │ ├── images.html │ │ ├── img │ │ │ ├── cam-secure-02.png │ │ │ ├── cam-secure-03.png │ │ │ └── cam-secure.png │ │ ├── import-link.html │ │ ├── import.html │ │ ├── index-amd.html │ │ ├── index-large.html │ │ ├── index-urls.html │ │ ├── index.html │ │ ├── inputs.html │ │ ├── js │ │ │ ├── default.js │ │ │ └── main.js │ │ ├── less.html │ │ ├── less │ │ │ └── bootstrap.less │ │ ├── links.html │ │ ├── plugin.js │ │ ├── proxy-headers.html │ │ ├── proxy-ip.html │ │ ├── proxy-vhost.html │ │ ├── rewrites │ │ │ ├── comment.expected.html │ │ │ ├── comment.html │ │ │ ├── escaped.1.expected.html │ │ │ ├── escaped.1.html │ │ │ ├── hashes.expected.html │ │ │ └── hashes.input.html │ │ ├── sass.html │ │ ├── scrolling.html │ │ ├── scss │ │ │ └── bootstrap-scss.scss │ │ ├── socket.io.html │ │ ├── stylus │ │ │ └── bootstrap.styl │ │ ├── svg.html │ │ ├── svg │ │ │ └── bin.svg │ │ ├── tailwind │ │ │ ├── index.html │ │ │ └── tailwind.min.css │ │ ├── test.txt │ │ ├── test2.txt │ │ ├── username.github.io │ │ │ └── index.html │ │ └── watch-func.txt │ ├── fixtures2 │ │ └── style-alt.css │ ├── protractor │ │ ├── _run.js │ │ ├── bs.init.js │ │ ├── config.multi.js │ │ ├── config.single.js │ │ ├── logger.js │ │ ├── runProtractor.js │ │ ├── setup.js │ │ ├── setup.single.js │ │ ├── tests.multi.js │ │ ├── tests.single.js │ │ ├── tests │ │ │ ├── actions.clicks.js │ │ │ ├── actions.scroll.js │ │ │ ├── proxy.interactions.js │ │ │ ├── proxy.rewrites.js │ │ │ ├── server.interactions.js │ │ │ ├── snippet.injection.js │ │ │ ├── with.baseurl.https.js │ │ │ ├── with.baseurl.js │ │ │ └── with.socket.io.js │ │ └── utils.js │ ├── specs │ │ ├── api │ │ │ ├── init.active.js │ │ │ ├── init.exit.js │ │ │ ├── init.js │ │ │ ├── init.notify.js │ │ │ ├── init.pause.js │ │ │ ├── init.reload.deprecated.js │ │ │ ├── init.reload.js │ │ │ ├── init.reload.multi.js │ │ │ ├── init.reload.stream.js │ │ │ ├── init.reload.stream.noop.js │ │ │ ├── init.returns.js │ │ │ ├── init.sockets.js │ │ │ └── watch.js │ │ ├── cli │ │ │ ├── cli.exec.js │ │ │ ├── cli.get.config.js │ │ │ ├── cli.help.js │ │ │ ├── cli.info.js │ │ │ ├── cli.options.files.js │ │ │ ├── cli.options.ghost.js │ │ │ ├── cli.options.ignore.js │ │ │ ├── cli.options.ports.js │ │ │ ├── cli.options.proxy.js │ │ │ ├── cli.options.server.js │ │ │ ├── cli.options.watch.js │ │ │ └── cli.options.watchOptions.cwd.js │ │ ├── commands │ │ │ ├── recipes.js │ │ │ └── reload.js │ │ ├── e2e │ │ │ ├── cli │ │ │ │ ├── e2e.cli.conf.js │ │ │ │ ├── e2e.cli.error.js │ │ │ │ ├── e2e.cli.files.js │ │ │ │ ├── e2e.cli.init.js │ │ │ │ ├── e2e.cli.plugins.js │ │ │ │ ├── e2e.cli.proxy.js │ │ │ │ ├── e2e.cli.proxy.ws.js │ │ │ │ ├── e2e.cli.server.js │ │ │ │ ├── e2e.cli.snippet.js │ │ │ │ └── e2e.cli.ui.js │ │ │ ├── commands.server.json │ │ │ ├── e2e.events.js │ │ │ ├── e2e.fail.js │ │ │ ├── e2e.online.js │ │ │ ├── e2e.options.callbacks.js │ │ │ ├── e2e.options.cors.js │ │ │ ├── e2e.options.js │ │ │ ├── e2e.options.logPrefix.js │ │ │ ├── e2e.options.logSnippet.js │ │ │ ├── e2e.options.open.browsers.js │ │ │ ├── e2e.options.open.js │ │ │ ├── e2e.options.port.js │ │ │ ├── e2e.options.script.async.js │ │ │ ├── e2e.options.scriptpath.js │ │ │ ├── e2e.options.serveStatic.js │ │ │ ├── e2e.options.single.js │ │ │ ├── e2e.options.snippet.js │ │ │ ├── e2e.options.sockets.js │ │ │ ├── e2e.options.startPath.js │ │ │ ├── e2e.snippet.js │ │ │ ├── files │ │ │ │ ├── e2e.file.changed.js │ │ │ │ ├── e2e.file.options.js │ │ │ │ └── e2e.file.watching.js │ │ │ ├── middleware │ │ │ │ ├── middleware.option.js │ │ │ │ ├── middleware.proxy.option.js │ │ │ │ └── middleware.server.option.js │ │ │ ├── proxy │ │ │ │ ├── e2e.proxy.cookies.js │ │ │ │ ├── e2e.proxy.error.js │ │ │ │ ├── e2e.proxy.external.js │ │ │ │ ├── e2e.proxy.js │ │ │ │ ├── e2e.proxy.proxy.options.js │ │ │ │ ├── e2e.proxy.req.headers.js │ │ │ │ ├── e2e.proxy.req.headers.obj.js │ │ │ │ ├── e2e.proxy.rewrite.rules.add.js │ │ │ │ ├── e2e.proxy.rewrite.rules.js │ │ │ │ ├── e2e.proxy.rewrite.rules.remove.js │ │ │ │ ├── e2e.proxy.rewrite.rules.replace.js │ │ │ │ ├── e2e.proxy.secure.js │ │ │ │ ├── e2e.proxy.snippet.js │ │ │ │ └── e2e.proxy.ws.js │ │ │ └── server │ │ │ │ ├── e2e.server.404.js │ │ │ │ ├── e2e.server.dirs.js │ │ │ │ ├── e2e.server.httpModule.js │ │ │ │ ├── e2e.server.js │ │ │ │ ├── e2e.server.middleware.js │ │ │ │ ├── e2e.server.newapi.js │ │ │ │ ├── e2e.server.newapi2.js │ │ │ │ ├── e2e.server.rewrite.rules.add.js │ │ │ │ ├── e2e.server.rewrite.rules.js │ │ │ │ ├── e2e.server.rewrite.rules.remove.js │ │ │ │ ├── e2e.server.rewrite.rules.replace.js │ │ │ │ ├── e2e.server.routes.js │ │ │ │ ├── e2e.server.secure.custom.js │ │ │ │ ├── e2e.server.secure.js │ │ │ │ ├── e2e.server.secure.pfx.js │ │ │ │ ├── e2e.server.serveStatic.extensions.js │ │ │ │ ├── e2e.server.serveStatic.js │ │ │ │ └── e2e.server.tunnel.js │ │ ├── files │ │ │ ├── files.event-handler.js │ │ │ ├── files.watching.debounce.js │ │ │ ├── files.watching.delay.js │ │ │ └── files.watching.js │ │ ├── hooks │ │ │ └── files.watch.hook.js │ │ ├── http-protocol │ │ │ └── http.reload.js │ │ ├── instances │ │ │ ├── multi.emitter.js │ │ │ ├── multi.get.js │ │ │ ├── multi.has.js │ │ │ ├── multi.init.js │ │ │ ├── multi.js │ │ │ ├── multi.plugins.js │ │ │ ├── multi.proxy.js │ │ │ └── single.js │ │ ├── logger │ │ │ ├── logger.baseDir.js │ │ │ └── logger.files.changed.js │ │ ├── options │ │ │ └── options.set.js │ │ ├── plugins │ │ │ ├── bs.options.js │ │ │ ├── connector.js │ │ │ ├── files.js │ │ │ ├── hooks.js │ │ │ ├── logger.js │ │ │ ├── options.js │ │ │ ├── ui.error.js │ │ │ ├── ui.js │ │ │ ├── user.plugins.add.middleware.js │ │ │ ├── user.plugins.cleanup.js │ │ │ ├── user.plugins.error.js │ │ │ ├── user.plugins.inline.enabled.js │ │ │ ├── user.plugins.inline.error.js │ │ │ ├── user.plugins.inline.js │ │ │ ├── user.plugins.inline.obj.js │ │ │ ├── user.plugins.inline.obj.reference.js │ │ │ ├── user.plugins.inline.options.js │ │ │ ├── user.plugins.js │ │ │ ├── user.plugins.proxy.js │ │ │ └── user.plugins.serve.files.js │ │ ├── resp-mod │ │ │ └── rewrite-links.js │ │ ├── server │ │ │ └── server.snippet.js │ │ └── utils │ │ │ ├── utils.connect.js │ │ │ ├── utils.default.callback.js │ │ │ ├── utils.fail.js │ │ │ ├── utils.getHostIp.js │ │ │ ├── utils.getUrl.js │ │ │ ├── utils.getUrls.js │ │ │ ├── utils.js │ │ │ ├── utils.setUrlOptions.js │ │ │ └── utils.verifyOptions.js │ └── utils.js │ └── tsconfig.json ├── playwright.config.ts └── tests ├── examples ├── basic │ └── basic.spec.ts ├── html-inject │ └── html-inject.spec.ts ├── snippet │ └── snippet.spec.ts └── tailwind │ └── tailwind.spec.ts └── utils.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{css,js}] 12 | indent_size = 4 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | npm-debug.log 4 | .sass-cache 5 | test/fixtures/files/* 6 | test/fixtures/js/* 7 | example.server.js 8 | example.proxy.js 9 | example.snippet.js 10 | example.js 11 | .DS_store 12 | doc/ 13 | .coveralls.yml 14 | coverage/ 15 | /screenshots 16 | test/fixtures/multi/ 17 | before.json 18 | after.json 19 | bs-config.js 20 | /lodash.custom.min.js 21 | /dist 22 | /cypress/videos 23 | /cypress/screenshots/* 24 | client/dist/index.js 25 | client/dist/index.js.map 26 | client/dist/index.min.js 27 | client/dist/index.min.js.map 28 | node_modules/ 29 | /test-results/ 30 | /playwright-report/ 31 | /playwright/.cache/ 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | git: 2 | depth: 2 3 | language: node_js 4 | node_js: 5 | - "14" 6 | - "12" 7 | - "10" 8 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Issue details 2 | 3 | _Please provide issue details here_. 4 | 5 | ### Steps to reproduce/test case 6 | 7 | _Please provide necessary steps for reproduction of this issue, or better the 8 | reduced test case (without any external dependencies)_. 9 | 10 | ### Please specify which version of Browsersync, node and npm you're running 11 | 12 | - Browsersync [ ] 13 | - Node [ ] 14 | - Npm [ ] 15 | 16 | ### Affected platforms 17 | 18 | - [ ] linux 19 | - [ ] windows 20 | - [ ] OS X 21 | - [ ] freebsd 22 | - [ ] solaris 23 | - [ ] other _(please specify which)_ 24 | 25 | ### Browsersync use-case 26 | 27 | - [ ] API 28 | - [ ] Gulp 29 | - [ ] Grunt 30 | - [ ] CLI 31 | 32 | ### If CLI, please paste the entire command below 33 | 34 | {cli command here} 35 | 36 | ### for all other use-cases, (gulp, grunt etc), please show us exactly how you're using Browsersync 37 | 38 | {Browsersync init code here} 39 | -------------------------------------------------------------------------------- /examples/404.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will redirect all 404 requests to a 10 | * custom 404.html page 11 | * 12 | */ 13 | 14 | "use strict"; 15 | 16 | var browserSync = require("browser-sync").create(); 17 | 18 | browserSync.init( 19 | { 20 | files: ["app/css/*.css"], 21 | server: { 22 | baseDir: "app" 23 | } 24 | }, 25 | function(err, bs) { 26 | bs.addMiddleware("*", function(req, res) { 27 | res.writeHead(302, { 28 | location: "404.html" 29 | }); 30 | res.end("Redirecting!"); 31 | }); 32 | } 33 | ); 34 | -------------------------------------------------------------------------------- /examples/basic/run.js: -------------------------------------------------------------------------------- 1 | const bs = require("../../packages/browser-sync/dist/index").create(); 2 | const path = require("path"); 3 | const serverDir = path.join(__dirname, "..", "..", "packages/browser-sync/test/fixtures"); 4 | 5 | bs.init( 6 | { 7 | server: serverDir, 8 | open: false, 9 | watch: true, 10 | online: false 11 | }, 12 | (err, bs) => { 13 | const message = { 14 | kind: "ready", 15 | urls: bs.options.get("urls").toJS(), 16 | cwd: serverDir 17 | }; 18 | if (process.send) { 19 | process.send(message); 20 | } else { 21 | console.log(message); 22 | } 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /examples/callback.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example shows how you can access information about Browsersync when it's running 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | var config = { 18 | proxy: "localhost:8000", 19 | files: ["app/css/*.css"] 20 | }; 21 | 22 | browserSync.init(config, function(err, bs) { 23 | // Full access to Browsersync object here 24 | console.log(bs.getOption("urls")); 25 | }); 26 | -------------------------------------------------------------------------------- /examples/express.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync express 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server & use the `app` directory as the root 10 | * + use any custom routes you have registered with Express 11 | * 12 | */ 13 | 14 | "use strict"; 15 | 16 | var bs = require("browser-sync").create(); 17 | var express = require("express"); 18 | var router = express.Router(); 19 | var app = express(); 20 | 21 | /** 22 | * Catch a route like /user/2324 23 | * and send a JSON response 24 | */ 25 | router.get("/user/:id", function(req, res) { 26 | res.send({ 27 | name: "shane", 28 | pets: ["cat", "hippo"], 29 | id: req.params.id 30 | }); 31 | }); 32 | 33 | /** 34 | * Register the route with Express 35 | */ 36 | app.use(router); 37 | 38 | /** 39 | * Start the Browsersync server and 40 | * load the express app as middleware 41 | */ 42 | bs.init({ 43 | server: "./app", 44 | middleware: [app] 45 | }); 46 | -------------------------------------------------------------------------------- /examples/less.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will serve .less files 10 | * and allow them to be injected as a css file would be. 11 | * 12 | */ 13 | 14 | "use strict"; 15 | 16 | var browserSync = require("browser-sync").create(); 17 | 18 | browserSync.init({ 19 | server: ["test/fixtures"], 20 | open: false, 21 | watch: true, 22 | injectFileTypes: ["css", "less"], 23 | middleware: [ 24 | (req, res, next) => { 25 | if (req.url.indexOf("bootstrap.less") > -1) { 26 | res.setHeader("content-type", "text/css"); 27 | } 28 | next(); 29 | } 30 | ] 31 | }); 32 | -------------------------------------------------------------------------------- /examples/notify-styles.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | */ 10 | 11 | "use strict"; 12 | 13 | var browserSync = require("../").create(); 14 | 15 | browserSync.init({ 16 | open: false, // Stop auto open browser 17 | notify: { 18 | styles: [ 19 | "display: none;", 20 | "padding: 6px 15px 3px;", 21 | "position: fixed;", 22 | "font-size: 40px;", 23 | "z-index: 9999;", 24 | "left: 0px;", 25 | "bottom: 0px;", 26 | "color: rgb(74, 74, 74);", 27 | "background-color: rgb(17, 17, 17);", 28 | "color: rgb(229, 229, 229);" 29 | ] 30 | }, 31 | server: { 32 | baseDir: "test/fixtures" 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /examples/options.snippetOptions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example shows how you can place the snippet anywhere. 10 | */ 11 | 12 | "use strict"; 13 | 14 | var path = require("path"); 15 | var browserSync = require("../packages/browser-sync").create(); 16 | var cwd = path.join(__dirname, ".."); 17 | var fixtures_dir = path.join(cwd, "packages/browser-sync/test/fixtures"); 18 | 19 | browserSync.init({ 20 | files: [path.join(fixtures_dir, "css/*.css")], 21 | server: fixtures_dir, 22 | snippetOptions: { 23 | rule: { 24 | match: /<\/head>/i, 25 | fn: function (snippet, match) { 26 | return snippet + match; 27 | }, 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /examples/proxy.gzip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync compression 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will proxy to your existing vhost 10 | * and serve gzipped responses 11 | * 12 | */ 13 | 14 | "use strict"; 15 | 16 | var browserSync = require("browser-sync").create(); 17 | var compression = require("compression"); 18 | 19 | browserSync.init({ 20 | files: ["app/css/*.css"], 21 | proxy: { 22 | target: "http://yourlocal.dev", 23 | middleware: compression() 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /examples/proxy.headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example shows how to specify the proxy headers for each request 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | proxy: { 20 | target: "localhost:8000", 21 | reqHeaders: function(config) { 22 | /** 23 | * These are the default headers as a guide for you. 24 | * You can set whatever you want here. 25 | */ 26 | return { 27 | host: config.urlObj.host, 28 | "accept-encoding": "identity", 29 | agent: false 30 | }; 31 | } 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /examples/proxy.localhost.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will wrap your existing server in a proxy url. 10 | * Use the new Proxy url to access your site. 11 | * 12 | */ 13 | 14 | "use strict"; 15 | 16 | var browserSync = require("browser-sync").create(); 17 | 18 | browserSync.init({ 19 | files: ["app/css/*.css"], 20 | proxy: "localhost:8000" 21 | }); 22 | -------------------------------------------------------------------------------- /examples/proxy.middleware.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a proxy server and run middlewares 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | proxy: { 20 | target: "http://yourlocal.dev", 21 | middleware: function(req, res, next) { 22 | console.log(req.url); 23 | next(); 24 | } 25 | }, 26 | https: true 27 | }); 28 | -------------------------------------------------------------------------------- /examples/proxy.middleware.multi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a proxy server and run middlewares 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | var fn1 = function(req, res, next) { 18 | console.log(req.url); 19 | next(); 20 | }; 21 | 22 | var fn2 = function(req, res, next) { 23 | console.log(req.headers); 24 | next(); 25 | }; 26 | 27 | browserSync.init({ 28 | files: ["app/css/*.css"], 29 | proxy: { 30 | target: "http://yourlocal.dev", 31 | middleware: [fn1, fn2] 32 | }, 33 | https: true 34 | }); 35 | -------------------------------------------------------------------------------- /examples/proxy.proxyRes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will proxy http://www.bbc.co.uk and 10 | * add headers to the response *after* it's returned from 11 | * the server. 12 | */ 13 | 14 | "use strict"; 15 | 16 | var browserSync = require("browser-sync").create(); 17 | 18 | browserSync.init({ 19 | proxy: { 20 | target: "http://www.bbc.co.uk", 21 | proxyRes: [ 22 | function(res) { 23 | res.headers["cache-control"] = "private"; 24 | } 25 | ] 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /examples/proxy.rewriteRules.simple.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync serve-static 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will 10 | * 1. create a proxy server for a live magento website 11 | * 2. serve static assets from your local `assets` directory 12 | * 3. rewrite HTML on the fly to make the live site use your local assets/css/core.css file 13 | * 14 | * eg: 15 | * becomes: 16 | * 17 | * 4. watch files in the assets directory and reload/inject when anything changes 18 | */ 19 | 20 | "use strict"; 21 | 22 | var browserSync = require("browser-sync").create(); 23 | 24 | browserSync.init({ 25 | proxy: "http://www.magento-site.com", 26 | files: ["assets"], 27 | middleware: require("serve-static")("."), 28 | rewriteRules: [ 29 | { 30 | match: "skin/frontend/rwd/assets/css/core.min.css", 31 | replace: "assets/css/core.css" 32 | } 33 | ] 34 | }); 35 | -------------------------------------------------------------------------------- /examples/proxy.secure.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a proxy server using https 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | proxy: "https://yourlocal.dev" 20 | }); 21 | -------------------------------------------------------------------------------- /examples/proxy.vhost.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will wrap your existing server in a proxy url. 10 | * Use the new Proxy url to access your site. 11 | * 12 | */ 13 | 14 | var browserSync = require("browser-sync").create(); 15 | 16 | browserSync.init({ 17 | files: "app/css/*.css", 18 | proxy: "yourvhost.dev" 19 | }); 20 | -------------------------------------------------------------------------------- /examples/server.basedir.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server & use the `app` directory as the root 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | server: { 20 | baseDir: "app" 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /examples/server.basedir.mulitple.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server & use the `app` & `dist` directories for serving files 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | server: { 20 | baseDir: ["app", "dist"] 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /examples/server.default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server in the cwd. 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | server: true 20 | }); 21 | -------------------------------------------------------------------------------- /examples/server.gzip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync compression 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server with gzip enabled 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | var compression = require("compression"); 17 | 18 | browserSync.init({ 19 | files: ["app/css/*.css"], 20 | server: { 21 | baseDir: "app", 22 | middleware: compression() 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /examples/server.http2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync http2 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server using http2 using the default information & use the `app` directory as the root 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | server: { 20 | baseDir: "app" 21 | }, 22 | https: true, 23 | httpModule: "http2" 24 | }); 25 | -------------------------------------------------------------------------------- /examples/server.latency.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server & use the `app` directory as the root 10 | * - any requests beginning with /json will have fake latency applied 11 | * - for 3 seconds 12 | * 13 | */ 14 | 15 | "use strict"; 16 | 17 | var browserSync = require("browser-sync").create(); 18 | 19 | function fakeLatency(req, res, next) { 20 | if (req.url.match(/^\/json/)) { 21 | setTimeout(next, 3000); 22 | } else { 23 | next(); 24 | } 25 | } 26 | 27 | browserSync.init({ 28 | files: ["app/css/*.css"], 29 | server: "app", 30 | middleware: [fakeLatency] 31 | }); 32 | -------------------------------------------------------------------------------- /examples/server.middleware.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server & use the `app` directory as the root 10 | * + use your custom middleware. Note: middleware will be added before 11 | * any Browsersync middlewares 12 | * 13 | */ 14 | 15 | "use strict"; 16 | 17 | var browserSync = require("browser-sync").create(); 18 | 19 | browserSync.init({ 20 | files: ["app/css/*.css"], 21 | server: { 22 | baseDir: "app", 23 | middleware: function(req, res, next) { 24 | console.log("hi from the middleware"); 25 | next(); 26 | } 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /examples/server.middleware.multiple.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server & use the `app` directory as the root 10 | * + use your custom middleware. Note: middleware will be added before 11 | * any Browsersync middlewares 12 | * 13 | */ 14 | 15 | "use strict"; 16 | 17 | var browserSync = require("browser-sync").create(); 18 | 19 | browserSync.init({ 20 | files: ["app/css/*.css"], 21 | server: { 22 | baseDir: "app", 23 | middleware: [ 24 | function(req, res, next) { 25 | console.log("hi from the first middleware"); 26 | next(); 27 | }, 28 | function(req, res, next) { 29 | console.log("hi from the second middleware"); 30 | next(); 31 | } 32 | ] 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /examples/server.proxy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync express http-proxy-middleware 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server in the cwd whilst proxying requests 10 | * to /api to a backend 11 | * 12 | */ 13 | 14 | "use strict"; 15 | 16 | var browserSync = require("browser-sync").create(); 17 | var express = require('express'); 18 | var proxy = require('http-proxy-middleware'); 19 | 20 | var app = express(); 21 | 22 | app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true})); 23 | 24 | browserSync.init({ 25 | server: ".", 26 | watch: true, 27 | middleware: [app] 28 | }); 29 | -------------------------------------------------------------------------------- /examples/server.secure.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server using https using the default information & use the `app` directory as the root 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | server: { 20 | baseDir: "app" 21 | }, 22 | https: true 23 | }); 24 | -------------------------------------------------------------------------------- /examples/server.secure.pfx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server using https using a PFX certificate & use the `app` directory as the root 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | files: ["app/css/*.css"], 19 | server: { 20 | baseDir: "app" 21 | }, 22 | https: { 23 | pfx: "certs/browsersync.pfx" 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /examples/server.watch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Install: 4 | * npm install browser-sync 5 | * 6 | * Run: 7 | * node 8 | * 9 | * This example will create a server using https using the default information & use the `app` directory as the root 10 | * 11 | */ 12 | 13 | "use strict"; 14 | 15 | var browserSync = require("browser-sync").create(); 16 | 17 | browserSync.init({ 18 | server: "test/fixtures", 19 | watch: true 20 | }); 21 | -------------------------------------------------------------------------------- /examples/snippet/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | Document 11 | 12 | 13 |

Hello world

14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/snippet/run.js: -------------------------------------------------------------------------------- 1 | const bs = require("../../packages/browser-sync/dist/index").create(); 2 | bs.init( 3 | { 4 | server: ".", 5 | open: false, 6 | notify: false, 7 | watch: true, 8 | snippetOptions: { 9 | rule: { 10 | match: /<\/head>/i, 11 | fn: function(snippet, match) { 12 | return snippet + match; 13 | } 14 | } 15 | } 16 | }, 17 | (err, bs) => { 18 | const message = { 19 | kind: "ready", 20 | urls: bs.options.get("urls").toJS(), 21 | cwd: __dirname 22 | }; 23 | if (process.send) { 24 | process.send(message); 25 | } else { 26 | console.log(message); 27 | } 28 | } 29 | ); 30 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "3.0.4" 6 | } 7 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasksRunnerOptions": { 3 | "default": { 4 | "runner": "nx/tasks-runners/default", 5 | "options": { 6 | "cacheableOperations": [ 7 | "build" 8 | ] 9 | } 10 | } 11 | }, 12 | "targetDefaults": { 13 | "build": { 14 | "dependsOn": [ 15 | "^build" 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "browser-sync-mono", 4 | "scripts": { 5 | "bootstrap": "lerna bootstrap", 6 | "postinstall": "npm run bootstrap", 7 | "test": "lerna run build && lerna run test --scope browser-sync", 8 | "test:e2e": "echo skipping cypress", 9 | "test:playwright": "playwright test" 10 | }, 11 | "devDependencies": { 12 | "lerna": "^6.1.0" 13 | }, 14 | "dependencies": { 15 | "@playwright/test": "^1.43.0", 16 | "rxjs": "^7.5.4", 17 | "zod": "^3.22.2" 18 | }, 19 | "nx": {} 20 | } 21 | -------------------------------------------------------------------------------- /packages/browser-sync-client/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | test/coverage 4 | example.proxy.js 5 | /dist/* 6 | /_dist/* 7 | -------------------------------------------------------------------------------- /packages/browser-sync-client/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | git: 3 | depth: 2 4 | language: node_js 5 | node_js: 6 | - node 7 | - '4.0.0' 8 | before_script: 9 | - "npm install -g gulp" 10 | - "export DISPLAY=:99.0" 11 | - "sh -e /etc/init.d/xvfb start" 12 | -------------------------------------------------------------------------------- /packages/browser-sync-client/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Shane Osbourne 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /packages/browser-sync-client/README.md: -------------------------------------------------------------------------------- 1 | # browser-sync-client [![Build Status](https://travis-ci.org/BrowserSync/browser-sync-client.svg)](https://travis-ci.org/BrowserSync/browser-sync-client) 2 | 3 | Client-side script for BrowserSync 4 | 5 | ## Contributors 6 | 7 | ``` 8 | 177 Shane Osbourne 9 | 2 Sergey Slipchenko 10 | 1 Hugo Dias 11 | 1 Shinnosuke Watanabe 12 | 1 Tim Schaub 13 | 1 Shane Daniel 14 | 1 Matthieu Vachon 15 | ``` 16 | 17 | ## License 18 | Copyright (c) 2014 Shane Osbourne 19 | Licensed under the MIT license. 20 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/dom-effects.ts: -------------------------------------------------------------------------------- 1 | import { BehaviorSubject } from "rxjs/BehaviorSubject"; 2 | import { propSetDomEffect } from "./dom-effects/prop-set.dom-effect"; 3 | import { styleSetDomEffect } from "./dom-effects/style-set.dom-effect"; 4 | import { linkReplaceDomEffect } from "./dom-effects/link-replace.dom-effect"; 5 | import { setScrollDomEffect } from "./dom-effects/set-scroll.dom-effect"; 6 | import { setWindowNameDomEffect } from "./dom-effects/set-window-name.dom-effect"; 7 | 8 | export enum Events { 9 | PropSet = "@@BSDOM.Events.PropSet", 10 | StyleSet = "@@BSDOM.Events.StyleSet", 11 | LinkReplace = "@@BSDOM.Events.LinkReplace", 12 | SetScroll = "@@BSDOM.Events.SetScroll", 13 | SetWindowName = "@@BSDOM.Events.SetWindowName" 14 | } 15 | 16 | export const domHandlers$ = new BehaviorSubject({ 17 | [Events.PropSet]: propSetDomEffect, 18 | [Events.StyleSet]: styleSetDomEffect, 19 | [Events.LinkReplace]: linkReplaceDomEffect, 20 | [Events.SetScroll]: setScrollDomEffect, 21 | [Events.SetWindowName]: setWindowNameDomEffect 22 | }); 23 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/dom-effects/prop-set.dom-effect.ts: -------------------------------------------------------------------------------- 1 | import { map } from "rxjs/operators/map"; 2 | import { tap } from "rxjs/operators/tap"; 3 | import { Observable } from "rxjs/Observable"; 4 | import { Events } from "../dom-effects"; 5 | import * as Log from "../log"; 6 | 7 | export interface PropSetPayload { 8 | target: Element; 9 | prop: string; 10 | value: string; 11 | pathname: string; 12 | } 13 | 14 | export function propSetDomEffect(xs: Observable) { 15 | return xs.pipe( 16 | tap(event => { 17 | const { target, prop, value } = event; 18 | target[prop] = value; 19 | }), 20 | map(e => 21 | Log.consoleInfo(`[PropSet]`, e.target, `${e.prop} = ${e.pathname}`) 22 | ) 23 | ); 24 | } 25 | 26 | export function propSet(incoming: PropSetPayload): [Events.PropSet, any] { 27 | return [Events.PropSet, incoming]; 28 | } 29 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/dom-effects/set-scroll.dom-effect.ts: -------------------------------------------------------------------------------- 1 | import { Inputs } from "../index"; 2 | import { ignoreElements } from "rxjs/operators/ignoreElements"; 3 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 4 | import { tap } from "rxjs/operators/tap"; 5 | import { Observable } from "rxjs/Observable"; 6 | import { Events } from "../dom-effects"; 7 | 8 | export type SetScrollPayload = { x: number; y: number }; 9 | 10 | export function setScroll( 11 | x: number, 12 | y: number 13 | ): [Events.SetScroll, SetScrollPayload] { 14 | return [Events.SetScroll, { x, y }]; 15 | } 16 | 17 | export function setScrollDomEffect( 18 | xs: Observable, 19 | inputs: Inputs 20 | ) { 21 | return xs.pipe( 22 | withLatestFrom(inputs.window$), 23 | tap(([event, window]) => window.scrollTo(event.x, event.y)), 24 | ignoreElements() 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/dom-effects/set-window-name.dom-effect.ts: -------------------------------------------------------------------------------- 1 | import { Inputs } from "../index"; 2 | import { ignoreElements } from "rxjs/operators/ignoreElements"; 3 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 4 | import { tap } from "rxjs/operators/tap"; 5 | import { Observable } from "rxjs/Observable"; 6 | import { Events } from "../dom-effects"; 7 | 8 | export function setWindowNameDomEffect(xs: Observable, inputs: Inputs) { 9 | return xs.pipe( 10 | withLatestFrom(inputs.window$), 11 | tap(([value, window]) => (window.name = value)), 12 | ignoreElements() 13 | ); 14 | } 15 | 16 | export function setWindowName( 17 | incoming: string 18 | ): [Events.SetWindowName, string] { 19 | return [Events.SetWindowName, incoming]; 20 | } 21 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/dom-effects/style-set.dom-effect.ts: -------------------------------------------------------------------------------- 1 | import { map } from "rxjs/operators/map"; 2 | import { Events } from "../dom-effects"; 3 | import { tap } from "rxjs/operators/tap"; 4 | import { Observable } from "rxjs/Observable"; 5 | import * as Log from "../log"; 6 | 7 | export interface StyleSetPayload { 8 | style: string; 9 | styleName: string; 10 | value: string; 11 | newValue: string; 12 | pathName: string; 13 | } 14 | 15 | export function styleSetDomEffect(xs: Observable) { 16 | return xs.pipe( 17 | tap(event => { 18 | const { style, styleName, newValue } = event; 19 | style[styleName] = newValue; 20 | }), 21 | map(e => Log.consoleInfo(`[StyleSet] ${e.styleName} = ${e.pathName}`)) 22 | ); 23 | } 24 | 25 | export function styleSet(incoming: StyleSetPayload): [Events.StyleSet, any] { 26 | return [Events.StyleSet, incoming]; 27 | } 28 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/effects/browser-reload.effect.ts: -------------------------------------------------------------------------------- 1 | import { EffectNames } from "../effects"; 2 | import { Inputs } from "../index"; 3 | import { Observable } from "rxjs/Observable"; 4 | import { tap } from "rxjs/operators/tap"; 5 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 6 | 7 | export function browserReload() { 8 | return [EffectNames.BrowserReload]; 9 | } 10 | 11 | export function preBrowserReload() { 12 | return [EffectNames.PreBrowserReload]; 13 | } 14 | 15 | export function browserReloadEffect(xs: Observable, inputs: Inputs) { 16 | return xs.pipe( 17 | withLatestFrom(inputs.window$), 18 | tap(([, window]) => window.location.reload()) 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/effects/file-reload.effect.ts: -------------------------------------------------------------------------------- 1 | import { FileReloadEventPayload } from "../types/socket"; 2 | import { EffectNames } from "../effects"; 3 | import { Inputs } from "../index"; 4 | import { reload } from "../vendor/Reloader"; 5 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 6 | import { mergeMap } from "rxjs/operators/mergeMap"; 7 | import { Observable } from "rxjs/Observable"; 8 | 9 | export function fileReload(event: FileReloadEventPayload) { 10 | return [EffectNames.FileReload, event]; 11 | } 12 | 13 | /** 14 | * Attempt to reload files in place 15 | * @param xs 16 | * @param inputs 17 | */ 18 | export function fileReloadEffect( 19 | xs: Observable, 20 | inputs: Inputs 21 | ) { 22 | return xs.pipe( 23 | withLatestFrom(inputs.option$, inputs.document$, inputs.navigator$), 24 | mergeMap(([event, options, document, navigator]) => { 25 | return reload(document, navigator)(event, { 26 | tagNames: options.tagNames, 27 | liveCSS: true, 28 | liveImg: true 29 | }); 30 | }) 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/effects/set-element-value.effect.ts: -------------------------------------------------------------------------------- 1 | import { Inputs } from "../index"; 2 | import { Observable } from "rxjs/Observable"; 3 | import * as KeyupEvent from "../messages/KeyupEvent"; 4 | import { tap } from "rxjs/operators/tap"; 5 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 6 | import { EffectNames } from "../effects"; 7 | 8 | export function setElementValueEffect( 9 | xs: Observable, 10 | inputs: Inputs 11 | ) { 12 | return xs.pipe( 13 | withLatestFrom(inputs.document$), 14 | tap(([event, document]) => { 15 | const elems = document.getElementsByTagName(event.tagName); 16 | const match = elems[event.index]; 17 | if (match) { 18 | (match as HTMLInputElement).value = event.value; 19 | } 20 | }) 21 | ); 22 | } 23 | 24 | export function setElementValue(event: KeyupEvent.IncomingPayload) { 25 | return [EffectNames.SetElementValue, event]; 26 | } 27 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/effects/set-options.effect.ts: -------------------------------------------------------------------------------- 1 | import { Inputs } from "../index"; 2 | import { Observable } from "rxjs/Observable"; 3 | import { ignoreElements } from "rxjs/operators/ignoreElements"; 4 | import { tap } from "rxjs/operators/tap"; 5 | import { map } from "rxjs/operators/map"; 6 | import { EffectNames } from "../effects"; 7 | import { consoleInfo } from "../log"; 8 | 9 | /** 10 | * Set the local client options 11 | * @param xs 12 | * @param inputs 13 | */ 14 | export function setOptionsEffect( 15 | xs: Observable, 16 | inputs: Inputs 17 | ) { 18 | return xs.pipe( 19 | tap(options => inputs.option$.next(options)), 20 | // map(() => consoleInfo('set options')) 21 | ignoreElements() 22 | ); 23 | } 24 | 25 | export function setOptions(options: IBrowserSyncOptions) { 26 | return [EffectNames.SetOptions, options]; 27 | } 28 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/listeners.ts: -------------------------------------------------------------------------------- 1 | import { merge } from "rxjs/observable/merge"; 2 | import { getFormInputStream } from "./listeners/form-inputs.listener"; 3 | import { getClickStream } from "./listeners/clicks.listener"; 4 | import { getScrollStream } from "./listeners/scroll.listener"; 5 | import { getFormTogglesStream } from "./listeners/form-toggles.listener"; 6 | import { OutgoingSocketEvent } from "./socket-messages"; 7 | import { Observable } from "rxjs/Observable"; 8 | import { Inputs } from "./index"; 9 | 10 | export function initListeners( 11 | window: Window, 12 | document: Document, 13 | socket$: Inputs["socket$"], 14 | option$: Inputs["option$"] 15 | ): Observable { 16 | const merged$ = merge( 17 | getScrollStream(window, document, socket$, option$), 18 | getClickStream(document, socket$, option$), 19 | getFormInputStream(document, socket$, option$), 20 | getFormTogglesStream(document, socket$, option$) 21 | ); 22 | 23 | return merged$; 24 | } 25 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/messages/BrowserLocation.ts: -------------------------------------------------------------------------------- 1 | import { Inputs } from "../index"; 2 | import { pluck } from "rxjs/operators/pluck"; 3 | import { filter } from "rxjs/operators/filter"; 4 | import { map } from "rxjs/operators/map"; 5 | import { Observable } from "rxjs/Observable"; 6 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 7 | import { browserSetLocation } from "../effects/browser-set-location.effect"; 8 | 9 | export interface IncomingPayload { 10 | url?: string; 11 | path?: number; 12 | } 13 | 14 | export function incomingBrowserLocation( 15 | xs: Observable, 16 | inputs: Inputs 17 | ) { 18 | return xs.pipe( 19 | withLatestFrom(inputs.option$.pipe(pluck("ghostMode", "location"))), 20 | filter(([, canSyncLocation]) => canSyncLocation === true), 21 | map(([event]) => browserSetLocation(event)) 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/messages/BrowserNotify.ts: -------------------------------------------------------------------------------- 1 | import { map } from "rxjs/operators/map"; 2 | import { Observable } from "rxjs/Observable"; 3 | import * as Log from "../log"; 4 | 5 | export interface IncomingPayload { 6 | message: string; 7 | timeout: number; 8 | override?: boolean; 9 | } 10 | 11 | export function incomingBrowserNotify(xs: Observable) { 12 | return xs.pipe(map(event => Log.overlayInfo(event.message, event.timeout))); 13 | } 14 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/messages/Connection.ts: -------------------------------------------------------------------------------- 1 | import { Inputs } from "../index"; 2 | import { pluck } from "rxjs/operators/pluck"; 3 | import { of } from "rxjs/observable/of"; 4 | import { Observable } from "rxjs/Observable"; 5 | import * as Log from "../log"; 6 | import { withLatestFrom } from "rxjs/operators/withLatestFrom"; 7 | import { mergeMap } from "rxjs/operators/mergeMap"; 8 | import { setOptions } from "../effects/set-options.effect"; 9 | 10 | export function incomingConnection( 11 | xs: Observable, 12 | inputs: Inputs 13 | ) { 14 | return xs.pipe( 15 | withLatestFrom(inputs.option$.pipe(pluck("logPrefix"))), 16 | mergeMap(([x, logPrefix]) => { 17 | 18 | const prefix = logPrefix 19 | ? `${logPrefix}: ` 20 | : ''; 21 | 22 | return of( 23 | setOptions(x), 24 | Log.overlayInfo(`${prefix}connected`) 25 | ); 26 | }) 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/messages/Disconnect.ts: -------------------------------------------------------------------------------- 1 | import { ignoreElements } from "rxjs/operators/ignoreElements"; 2 | import { Observable } from "rxjs/Observable"; 3 | import { tap } from "rxjs/operators/tap"; 4 | 5 | export function incomingDisconnect(xs: Observable) { 6 | return xs.pipe(tap(x => console.log(x)), ignoreElements()); 7 | } 8 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/messages/OptionsSet.ts: -------------------------------------------------------------------------------- 1 | import { map } from "rxjs/operators/map"; 2 | import { Observable } from "rxjs/Observable"; 3 | import { setOptions } from "../effects/set-options.effect"; 4 | import { tap } from "rxjs/operators/tap"; 5 | 6 | export interface Payload { 7 | options: IBrowserSyncOptions; 8 | path: string[]; 9 | value: any; 10 | } 11 | 12 | type IncomingPayload = Payload; 13 | 14 | export function incomingOptionsSet(xs: Observable) { 15 | return xs.pipe(map(event => setOptions(event.options))); 16 | } 17 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/types/socket.ts: -------------------------------------------------------------------------------- 1 | import {IncomingSocketNames} from "../socket-messages"; 2 | 3 | export type FileReloadEventPayload = { 4 | url?: string; 5 | ext: string; 6 | path: string; 7 | basename: string; 8 | event: string; 9 | type: 'inject' | 'reload'; 10 | } 11 | 12 | export type FileReloadEvent = [IncomingSocketNames.FileReload, FileReloadEventPayload]; 13 | -------------------------------------------------------------------------------- /packages/browser-sync-client/lib/vendor/Timer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * decaffeinate suggestions: 3 | * DS102: Remove unnecessary code created because of implicit returns 4 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md 5 | */ 6 | export class Timer { 7 | public running = false; 8 | public id: any; 9 | public _handler: any; 10 | 11 | constructor(public func) { 12 | this.id = null; 13 | this._handler = () => { 14 | this.running = false; 15 | this.id = null; 16 | return this.func(); 17 | }; 18 | } 19 | 20 | public start(timeout) { 21 | if (this.running) { clearTimeout(this.id); } 22 | this.id = setTimeout(this._handler, timeout); 23 | return this.running = true; 24 | } 25 | 26 | public stop() { 27 | if (this.running) { 28 | clearTimeout(this.id); 29 | this.running = false; return this.id = null; 30 | } 31 | } 32 | 33 | public static start (timeout, func) { 34 | setTimeout(func, timeout); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": "nofunc", 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": false, 10 | "unused": false, 11 | "quotmark": "double", 12 | "boss": true, 13 | "eqnull": true, 14 | "node": true, 15 | "globals": { 16 | "describe" : false, 17 | "it" : false, 18 | "expect" : false, 19 | "runs" : false, 20 | "waitsFor" : false, 21 | "beforeEach" : false, 22 | "afterEach" : false, 23 | "before" : false, 24 | "after" : false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/client-new/ghostmode.js: -------------------------------------------------------------------------------- 1 | describe("Ghost Mode", function(){ 2 | var ghostMode = window.__bs_ghost_mode__; 3 | var bs = window.__bs_stub__; 4 | it("Should init", function() { 5 | var spy = sinon.spy(ghostMode.plugins.scroll, "init"); 6 | ghostMode.init(bs); 7 | sinon.assert.called(spy); 8 | }); 9 | }); -------------------------------------------------------------------------------- /packages/browser-sync-client/test/client-new/stubs/bs.js: -------------------------------------------------------------------------------- 1 | var __bs_stub__ = { 2 | options: { 3 | notify: true, 4 | codeSync: true, 5 | ghostMode: { 6 | scroll: true, 7 | clicks: true, 8 | forms: { 9 | toggles: true, 10 | inputs: true, 11 | submit: true 12 | } 13 | } 14 | }, 15 | utils: { 16 | getScrollSpace: function () {}, 17 | getBrowserScrollPosition: function () {}, 18 | getBody: function () {}, 19 | getSingleElement: function () {}, 20 | getElementData: function () {}, 21 | forceChange: function () {} 22 | }, 23 | socket: { 24 | on: function(){}, 25 | emit: function(){} 26 | }, 27 | canSync: function(){ return true } 28 | }; 29 | 30 | var __bs_events__ = { 31 | addEvent: function(){}, 32 | triggerClick: function(){} 33 | }; -------------------------------------------------------------------------------- /packages/browser-sync-client/test/fixtures/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: grey; 3 | } -------------------------------------------------------------------------------- /packages/browser-sync-client/test/fixtures/index-urls.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 | 13 |

Hello from the test Page

14 | Forms 15 | Scrolling Window 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/fixtures/less.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 |

Hello from the test

13 | Forms 14 | Scrolling Window 15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/fixtures/links.html: -------------------------------------------------------------------------------- 1 | Link 2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /packages/browser-sync-client/test/fixtures/proxy-headers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 | 13 |

Hello from the test Page

14 | Forms 15 | Scrolling Window 16 | 17 |

Click me

18 |

19 | 20 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/fixtures/sass.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 |

Hello from the test

13 | Forms 14 | Scrolling Window 15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/karma.conf.ci.js: -------------------------------------------------------------------------------- 1 | // Config for travis 2 | var conf = require("./test.conf"); 3 | 4 | module.exports = function (config) { 5 | 6 | conf.logLevel = config.LOG_INFO; 7 | conf.autoWatch = false; 8 | conf.browsers = ["Firefox"]; 9 | conf.preprocessors = { 10 | "fixtures/*.html" : ["html2js"] 11 | }; 12 | conf.singleRun = true; 13 | 14 | config.set(conf); 15 | }; -------------------------------------------------------------------------------- /packages/browser-sync-client/test/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Sep 18 2013 18:10:53 GMT+0100 (BST) 3 | var conf = require("./test.conf"); 4 | 5 | module.exports = function (config) { 6 | conf.logLevel = config.LOG_INFO; 7 | config.set(conf); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/browser-sync-client/test/middleware/file.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var index = require("../../index.js"); 4 | 5 | var assert = require("chai").assert; 6 | var http = require("http"); 7 | 8 | describe("Using the file contents", function () { 9 | it("Returns a String", function () { 10 | var file = index.middleware({minify: true}, "UNIQSTRING", "file"); 11 | assert.isString(file); 12 | assert.isTrue(file.indexOf("UNIQSTRING") === 0); 13 | }); 14 | }); -------------------------------------------------------------------------------- /packages/browser-sync-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES5", 5 | "noImplicitAny": false, 6 | "preserveConstEnums": true, 7 | "moduleResolution": "node", 8 | "sourceMap": true, 9 | "outDir": "_dist", 10 | "allowJs": true, 11 | "esModuleInterop": true, 12 | "importHelpers": true, 13 | "lib": [ 14 | "es2015", 15 | "dom", 16 | "dom.iterable" 17 | ], 18 | "types": [] 19 | }, 20 | "include": [ 21 | "./lib" 22 | ], 23 | "exclude": [] 24 | } 25 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | charset = "utf8" 8 | 9 | 10 | [*.css] 11 | indent_style = space 12 | indent_size = 4 13 | trim_trailing_whitespace = true 14 | 15 | 16 | [*.js] 17 | indent_style = space 18 | indent_size = 4 19 | trim_trailing_whitespace = true 20 | quote_type = double 21 | 22 | 23 | [*.json] 24 | indent_style = space 25 | indent_size = 2 26 | trim_trailing_whitespace = true 27 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | npm-debug.log 4 | .DS_Store 5 | .sass-cache 6 | lib/bower_components 7 | example.proxy.js 8 | example.snippet.js 9 | static/*.html -------------------------------------------------------------------------------- /packages/browser-sync-ui/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "laxbreak": true, 6 | "latedef": "nofunc", 7 | "newcap": true, 8 | "noarg": true, 9 | "plusplus": true, 10 | "sub": true, 11 | "undef": true, 12 | "quotmark": "double", 13 | "unused": true, 14 | "indent": 4, 15 | "eqnull": true, 16 | "strict": false, 17 | "node": true, 18 | "browser": true, 19 | "mocha": true, 20 | "jasmine": true, 21 | "esnext": true, 22 | "globals": { 23 | "browser": false, 24 | "sinon": false, 25 | "___browserSync___": false, 26 | "assert": false, 27 | "by": false, 28 | "element": false, 29 | "protractor": false, 30 | "inject": false, 31 | "angular": false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/README.md: -------------------------------------------------------------------------------- 1 | # Browsersync UI [![Build Status](https://travis-ci.org/BrowserSync/UI.svg?branch=master)](https://travis-ci.org/BrowserSync/UI) 2 | 3 | Comes bundled with the Browsersync module (version `2.0.0` onwards). 4 | 5 | ## License 6 | Copyright (c) 2016 Shane Osbourne 7 | Licensed under the Apache 2.0 license. 8 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/async-tasks.js: -------------------------------------------------------------------------------- 1 | var async = require("./async"); 2 | 3 | module.exports = [ 4 | { 5 | step: "Setting default plugins", 6 | fn: async.initDefaultHooks 7 | }, 8 | { 9 | step: "Finding a free port", 10 | fn: async.findAFreePort 11 | }, 12 | { 13 | step: "Setting options also relevant to UI from BS", 14 | fn: async.setBsOptions 15 | }, 16 | { 17 | step: "Setting available URLS for UI", 18 | fn: async.setUrlOptions 19 | }, 20 | { 21 | step: "Starting the Control Panel Server", 22 | fn: async.startServer 23 | }, 24 | { 25 | step: "Add element events", 26 | fn: async.addElementEvents 27 | }, 28 | { 29 | step: "Registering default plugins", 30 | fn: async.registerPlugins 31 | }, 32 | { 33 | step: "Add options setting event", 34 | fn: async.addOptionsEvent 35 | } 36 | ]; -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/opts.js: -------------------------------------------------------------------------------- 1 | var Immutable = require("immutable"); 2 | 3 | var defaults = Immutable.fromJS({ 4 | port: 3001 5 | }); 6 | 7 | /** 8 | * @param {Object} obj 9 | * @returns {Map} 10 | */ 11 | module.exports.merge = function (obj) { 12 | return defaults.mergeDeep(Immutable.fromJS(obj)); 13 | }; 14 | 15 | /** 16 | * @param {Immutable.Map} obj 17 | * @returns {*} 18 | */ 19 | //function transformOptions(obj) { 20 | // 21 | // var out; 22 | // 23 | // Object.keys(transforms).forEach(function (key) { 24 | // out = obj.set(key, transforms[key](obj)); 25 | // }); 26 | // 27 | // return out; 28 | //} -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/connections/connections.directive.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 3 |

    {{connection.browser.name}} - ({{connection.browser.version}})

    4 | 9 |
  • 10 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/connections/connections.html: -------------------------------------------------------------------------------- 1 |
2 |

{{section.title}}

3 |
4 |
5 |
6 |

Connected devices/browsers will be listed here. If you are not seeing your device in the list, 7 | it's probably because the Browsersync script tag is not being loaded on your page.

8 |

9 | Browsersync works by injecting an asynchronous script tag (<script async>...</script>) right after the <body> tag during initial request. In order for this to work properly the <body> tag must be present. Alternatively you can provide a custom rule for the snippet using snippetOptions 10 |

11 |
12 |
13 | 14 |
15 | 18 |
19 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/connections/connections.plugin.js: -------------------------------------------------------------------------------- 1 | var connections = require("./lib/connections"); 2 | 3 | const PLUGIN_NAME = "Connections"; 4 | 5 | /** 6 | * @type {{plugin: Function, plugin:name: string, markup: string}} 7 | */ 8 | module.exports = { 9 | /** 10 | * @param {UI} ui 11 | * @param {BrowserSync} bs 12 | */ 13 | "plugin": function (ui, bs) { 14 | connections.init(ui, bs); 15 | }, 16 | /** 17 | * Hooks 18 | */ 19 | "hooks": { 20 | "client:js": fileContent("/connections.client.js"), 21 | "templates": [ 22 | getPath("/connections.directive.html") 23 | ] 24 | }, 25 | /** 26 | * Plugin name 27 | */ 28 | "plugin:name": PLUGIN_NAME 29 | }; 30 | 31 | /** 32 | * @param filepath 33 | * @returns {*} 34 | */ 35 | function getPath (filepath) { 36 | return require("path").join(__dirname, filepath); 37 | } 38 | 39 | /** 40 | * @param filepath 41 | * @returns {*} 42 | */ 43 | function fileContent (filepath) { 44 | return require("fs").readFileSync(getPath(filepath), "utf-8"); 45 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/help/help.client.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | const SECTION_NAME = "history"; 4 | 5 | angular 6 | .module("BrowserSync") 7 | .controller("HelpAboutController", [ 8 | "options", 9 | "pagesConfig", 10 | helpAboutController 11 | ]); 12 | 13 | /** 14 | * @param options 15 | * @param pagesConfig 16 | */ 17 | function helpAboutController(options, pagesConfig) { 18 | var ctrl = this; 19 | ctrl.options = options.bs; 20 | ctrl.section = pagesConfig[SECTION_NAME]; 21 | } 22 | 23 | })(angular); 24 | 25 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/help/help.directive.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/lib/plugins/help/help.directive.html -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/help/help.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ctrl.section.title}}

3 |
4 |
5 |
6 |

Help page

7 |
8 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/history/history.directive.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/history/history.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ctrl.section.title}}

3 |
4 |
5 | 9 |
10 |
11 |
12 |

Pages you navigate to will appear here - making it easy 13 | to sync all devices to a specific page

14 |
15 |
16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/network-throttle/network-throttle.directive.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | Creating a throttled server, please wait... 5 |

6 |
7 | 10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/overview/overview.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | {{ctrl.section.title}} 6 |

7 |
8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 |
17 |

Current Connections

18 |

Connected browsers will be listed here.

19 | 20 | 21 | 22 |
23 |
24 | 25 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/overview/snippet-info.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |

Place this snippet somewhere before the closing </body> tag in your website

7 |
{{options.snippet}}
8 | 9 |
10 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/compression.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 11 | 12 |
13 |
14 |
15 |

{{ctrl.compression.title}}

16 |

17 |
18 |
19 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/compression.js: -------------------------------------------------------------------------------- 1 | var Immutable = require("immutable"); 2 | 3 | module.exports.init = function (ui, bs) { 4 | 5 | var optPath = ["remote-debug", "compression"]; 6 | 7 | ui.setOptionIn(optPath, Immutable.Map({ 8 | name: "compression", 9 | title: "Compression", 10 | active: false, 11 | tagline: "Add Gzip Compression to all responses" 12 | })); 13 | 14 | var methods = { 15 | toggle: function (value) { 16 | if (value !== true) { 17 | value = false; 18 | } 19 | if (value) { 20 | ui.setOptionIn(optPath.concat("active"), true); 21 | bs.addMiddleware("", require("compression")(), {id: "ui-compression", override: true}); 22 | } else { 23 | ui.setOptionIn(optPath.concat("active"), false); 24 | bs.removeMiddleware("ui-compression"); 25 | } 26 | }, 27 | event: function (event) { 28 | methods[event.event](event.data); 29 | } 30 | }; 31 | 32 | return methods; 33 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/latency/latency.html: -------------------------------------------------------------------------------- 1 |
2 | 9 | 10 | 11 |
12 | 13 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/no-cache.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 11 | 12 |
13 |
14 |
15 |

{{ctrl.noCache.title}}

16 |

17 |
18 |
19 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/overlay-grid/css/grid-overlay-horizontal.css: -------------------------------------------------------------------------------- 1 | {{selector}}:after { 2 | position: absolute; 3 | width: auto; 4 | height: auto; 5 | z-index: 9999; 6 | content: ''; 7 | display: block; 8 | pointer-events: none; 9 | top: {{offsetY}}; 10 | right: 0; 11 | bottom: 0; 12 | left: {{offsetX}}; 13 | background-color: transparent; 14 | background-image: linear-gradient({{color}} 1px, transparent 1px); 15 | background-size: 100% {{size}}; 16 | } 17 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/overlay-grid/css/grid-overlay-vertical.css: -------------------------------------------------------------------------------- 1 | {{selector}}:before { 2 | position: absolute; 3 | width: auto; 4 | height: auto; 5 | z-index: 9999; 6 | content: ''; 7 | display: block; 8 | pointer-events: none; 9 | top: {{offsetY}}; 10 | right: 0; 11 | bottom: 0; 12 | left: {{offsetX}}; 13 | background-color: transparent; 14 | background-image: linear-gradient(90deg, {{color}} 1px, transparent 1px); 15 | background-size: {{size}} 100%; 16 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/overlay-grid/js/grid-overlay.js: -------------------------------------------------------------------------------- 1 | (function (window, bs, undefined) { 2 | 3 | var styleElem = bs.addDomNode({ 4 | placement: "head", 5 | attrs: { 6 | "type": "text/css", 7 | id: "__bs_overlay-grid-styles__" 8 | }, 9 | tagName: "style" 10 | }); 11 | 12 | bs.socket.on("ui:remote-debug:css-overlay-grid", function (data) { 13 | styleElem.innerHTML = data.innerHTML; 14 | }); 15 | 16 | bs.socket.emit("ui:remote-debug:css-overlay-grid:ready"); 17 | 18 | }(window, window.___browserSync___)); -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/remote-debug/remote-debug.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | {{ctrl.section.title}} 5 |

6 |
7 | 8 | 14 |
15 |
16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/plugins/sync-options/sync-options.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | {{ctrl.section.title}} 6 |

7 |
8 |
9 | 13 | 17 |
18 | 19 | 25 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/transform.options.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | module.exports = function (bs) { 4 | /** 5 | * Transform server options to offer additional functionality 6 | * @param bs 7 | */ 8 | 9 | var options = bs.options; 10 | var server = options.server; 11 | var cwd = bs.cwd; 12 | 13 | /** 14 | * Transform server option 15 | */ 16 | if (server) { 17 | if (Array.isArray(server.baseDir)) { 18 | server.baseDirs = options.server.baseDir.map(function (item) { 19 | return path.join(cwd, item); 20 | }); 21 | } else { 22 | server.baseDirs = [path.join(cwd, server.baseDir)]; 23 | } 24 | } 25 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/transforms.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "mode": function (obj) { 3 | if (obj.get("server")) { 4 | return "Server"; 5 | } 6 | if (obj.get("proxy")) { 7 | return "Proxy"; 8 | } 9 | return "Snippet"; 10 | } 11 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/urls.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/lib/urls.js -------------------------------------------------------------------------------- /packages/browser-sync-ui/lib/utils.js: -------------------------------------------------------------------------------- 1 | var url = require("url"); 2 | var http = require("http"); 3 | 4 | /** 5 | * @param localUrl 6 | * @param urlPath 7 | * @returns {*} 8 | */ 9 | function createUrl(localUrl, urlPath) { 10 | return url.parse(url.resolve(localUrl, urlPath)); 11 | } 12 | 13 | /** 14 | * @param url 15 | * @param cb 16 | */ 17 | function verifyUrl(url, cb) { 18 | 19 | url.headers = { 20 | "accept": "text/html" 21 | }; 22 | 23 | http.get(url, function (res) { 24 | if (res.statusCode === 200) { 25 | cb(null, res); 26 | } else { 27 | cb("not 200"); 28 | } 29 | }).on("error", function(e) { 30 | console.log("Got error: " + e.message); 31 | }); 32 | } 33 | 34 | module.exports.createUrl = createUrl; 35 | module.exports.verifyUrl = verifyUrl; 36 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/css/components.css: -------------------------------------------------------------------------------- 1 | svg { 2 | width: 100%; 3 | height: 100%; 4 | opacity: 1; 5 | fill: currentColor !important; 6 | -webkit-transition: .3s; 7 | transition: .3s; } 8 | svg.icon-hidden { 9 | opacity: 0; } 10 | 11 | body, html { 12 | height: auto; } 13 | 14 | .tube { 15 | padding: 0 14px; } 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/css/core.css: -------------------------------------------------------------------------------- 1 | 2 | /*# sourceMappingURL=core.css.map */ 3 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/css/core.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"core.css","sourceRoot":"/source/","sourcesContent":[]} -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/favicon.ico -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.eot -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.ttf -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.woff -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-bold-webfont.woff2 -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.eot -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.ttf -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.woff -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-it-webfont.woff2 -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.eot -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.ttf -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.woff -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/fonts/source-sans/sourcesanspro-regular-webfont.woff2 -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/img/favicon.ico -------------------------------------------------------------------------------- /packages/browser-sync-ui/public/img/ps-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync-ui/public/img/ps-bg.gif -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_includes/enable.disable.hbs: -------------------------------------------------------------------------------- 1 |
2 | 5 | 8 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_includes/form.input.checkbox.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_includes/form.input.text.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_includes/header.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_includes/icon.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_includes/nav.hbs: -------------------------------------------------------------------------------- 1 |
2 | 16 |
17 | {{ inc src="components/footer.hbs" }} 18 |
19 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_layouts/components.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: parent.hbs 3 | --- 4 |
5 | {{content}} 6 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_layouts/main.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: parent.hbs 3 | --- 4 | {{ inc src="../../public/img/icons/icons.svg" }} 5 |
6 | {{ inc src="components/header.hbs" }} 7 |
8 | {{ inc src="nav.hbs" }} 9 |
10 |
11 | {{ content }} 12 |
13 |
14 | {{ inc src="components/footer.hbs" }} 15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/_layouts/parent.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Browser Sync - Control Panel 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ $yield name="head" }} 12 | 13 | 14 | {{content}} 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/components/footer.hbs: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/components/heading.hbs: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ inc src="icon.hbs" icon="cog" }} 4 | Server Info 5 |

6 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/components/lists.hbs: -------------------------------------------------------------------------------- 1 |
2 |

Simple list

3 |
    4 |
  • Item 1
  • 5 |
  • Item 2
  • 6 |
  • Item 3
  • 7 |
  • Item 4
  • 8 |
  • Item 5
  • 9 |
10 |
11 |

Bordered list

12 | 19 |
20 |

Bordered list with controls

21 |
22 | 23 |
    24 | {{#each site.links}} 25 |
  • 26 |

    {{this}}

    27 |
    28 | 31 | 34 |
    35 |
  • 36 | {{/each}} 37 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/components/panels.hbs: -------------------------------------------------------------------------------- 1 |
2 |

Page heading

3 |
4 |

5 | {{ inc src="icon.hbs" icon="cog" }} 6 | Overview 7 |

8 |
9 |
10 |
11 |

12 | {{inc src="icon.hbs" icon="syncall"}} 13 | Sync all 14 |

15 |
16 |
17 | 21 | 25 |
26 |
27 | 28 |
29 |

30 | {{ inc src="icon.hbs" icon="cog" }} 31 | Overview 32 |

33 |
34 |
35 | 36 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/content/help.content.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Help / About" 3 | icon: "help" 4 | markdown: true 5 | --- 6 | {{inc src="components/help-content.hbs" }} 7 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/crossbow/help.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: main.hbs 3 | title: "Help / About" 4 | icon: "help" 5 | markdown: true 6 | --- 7 | {{inc src="components/help-content.hbs" }} 8 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/angular.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {angular} 3 | */ 4 | module.exports = window.angular; 5 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/directives.js: -------------------------------------------------------------------------------- 1 | var module = require("./module"); //jshint ignore:line 2 | 3 | module.directive("icon", require("./directives/icon")); 4 | module.directive("linkTo", require("./directives/link-to")); 5 | module.directive("switch", require("./directives/switch")); 6 | module.directive("newTab", require("./directives/new-tab")); -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/directives/icon.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | scope: { 4 | icon: "@" 5 | }, 6 | restrict: "E", 7 | replace: true, 8 | template: "", 9 | link: function (scope, elem, attrs) { 10 | scope.iconName = "#svg-" + scope.icon; 11 | return scope; 12 | } 13 | }; 14 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/directives/link-to.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | restrict: "E", 4 | replace: false, 5 | transclude: true, 6 | scope: { 7 | "path": "@" 8 | }, 9 | template: "as", 10 | controller: ["$scope", "$location", "$injector", function ($scope, $location, $injector) { 11 | 12 | var pages = $injector.get("pagesConfig"); 13 | var Pages = $injector.get("Pages"); 14 | 15 | $scope.navi = function (path) { 16 | var item = pages[path]; 17 | Pages.enable(item); 18 | $location.path(path); 19 | }; 20 | }] 21 | }; 22 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/directives/new-tab.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | scope: { 4 | url: "@", 5 | mode: "@" 6 | }, 7 | restrict: "E", 8 | replace: true, 9 | template: ' New Tab ' //jshint:ignore 10 | }; 11 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/directives/switch.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | scope: { 4 | toggle: "&", 5 | item: "=", 6 | switchid: "@", 7 | title: "@", 8 | tagline: "@", 9 | active: "=", 10 | prop: "@" 11 | }, 12 | restrict: "E", 13 | replace: true, 14 | transclude: true, 15 | templateUrl: "bs-switch.html", 16 | controllerAs: "ctrl", 17 | controller: ["$scope", function ($scope) { 18 | var ctrl = this; 19 | ctrl.item = $scope.item; 20 | }] 21 | }; 22 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/editor.js: -------------------------------------------------------------------------------- 1 | var Codemirror = require("codemirror"); 2 | var jsMode = require('codemirror/mode/javascript/javascript.js'); 3 | 4 | (function () { 5 | 6 | angular 7 | .module("bsEditor", []) 8 | .service('Editor', function () { 9 | return Codemirror; 10 | }); 11 | 12 | })(angular); 13 | 14 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/filters.js: -------------------------------------------------------------------------------- 1 | var module = require("./module"); //jshint ignore:line 2 | var utils = require("./utils"); //jshint ignore:line 3 | 4 | module 5 | .filter("ucfirst", function () { return utils.ucfirst; }) 6 | .filter("localRootUrl", function () { return utils.localRootUrl; }) 7 | .filter("localUrl", function () { return utils.localRootUrl; }) 8 | .filter("orderObjectBy", function () { return utils.orderObjectBy; }); -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {angular} 3 | */ 4 | module.exports = window.angular.module("BrowserSync"); 5 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/services/Options.js: -------------------------------------------------------------------------------- 1 | var app = require("../module"); 2 | 3 | app.factory("Options", ["Socket", OptionsService]); 4 | 5 | /** 6 | * @param Socket 7 | * @returns {{all: Function}} 8 | * @constructor 9 | */ 10 | function OptionsService(Socket) { 11 | 12 | return { 13 | all: function () { 14 | return Socket.getData("options"); 15 | } 16 | }; 17 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scripts/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ucfirst: function (string) { 3 | return string.charAt(0).toUpperCase() + string.slice(1); 4 | }, 5 | localRootUrl: function (port, scheme) { 6 | return [scheme, "://", window.location.hostname, ":", port].join(""); 7 | }, 8 | localUrl: function(path, port, mode) { 9 | if (mode === "snippet") { 10 | return path; 11 | } 12 | return ["//", window.location.hostname, ":", port, path].join(""); 13 | }, 14 | orderObjectBy: function (items, field, reverse) { 15 | var filtered = []; 16 | Object.keys(items).forEach(function(key) { 17 | filtered.push(items[key]); 18 | }); 19 | filtered.sort(function (a, b) { 20 | return (a[field] > b[field] ? 1 : -1); 21 | }); 22 | if (reverse) { 23 | filtered.reverse(); 24 | } 25 | return filtered; 26 | } 27 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/components.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @import "vars"; 4 | @import "modules/mixins"; 5 | @import "theme/svg"; 6 | 7 | body, html { 8 | height: auto; 9 | } 10 | 11 | .tube { 12 | padding: 0 $half-spacing; 13 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/core.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @import "vars"; 4 | 5 | @import "modules/mixins"; 6 | @import "modules/reset"; 7 | @import "vendor/normalize"; 8 | @import "vendor/fonts"; 9 | 10 | @import "theme/animations"; 11 | 12 | @import "theme/base"; 13 | @import "theme/grid"; 14 | @import "theme/cloak"; 15 | @import "theme/header"; 16 | @import "theme/sidebar"; 17 | @import "theme/section-nav"; 18 | @import "theme/main-content"; 19 | 20 | @import "theme/svg"; 21 | @import "theme/custom-icons"; 22 | @import "theme/headings"; 23 | @import "theme/paragraphs"; 24 | @import "theme/links"; 25 | @import "theme/helpers"; 26 | @import "theme/buttons"; 27 | @import "theme/forms"; 28 | @import 'theme/spinner'; 29 | @import "theme/panel"; 30 | @import "theme/lists"; 31 | @import "theme/top-bar"; 32 | @import "theme/state"; 33 | @import "theme/switch"; 34 | @import "theme/footer"; 35 | @import "theme/code"; 36 | @import "theme/notifications"; 37 | @import "theme/disconnect"; 38 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/modules/_reset.scss: -------------------------------------------------------------------------------- 1 | * { 2 | &, 3 | &:before, 4 | &:after{ 5 | box-sizing: border-box; 6 | } 7 | } 8 | 9 | h1,h2,h3,h4,h5,h6, 10 | p,blockquote,pre, 11 | dl,dd,ol,ul, 12 | form,fieldset,legend, 13 | table,th,td,caption, 14 | hr{ 15 | margin:0; 16 | padding:0; 17 | } 18 | 19 | abbr[title],dfn[title]{ 20 | cursor:help; 21 | } 22 | 23 | a,u,ins{ 24 | text-decoration:none; 25 | } 26 | 27 | ins{ 28 | border-bottom:1px solid; 29 | } 30 | 31 | img{ 32 | font-style:italic; 33 | } 34 | 35 | label, 36 | input, 37 | textarea, 38 | button, 39 | select, 40 | option{ 41 | cursor:pointer; 42 | } 43 | .text-input:active, 44 | .text-input:focus, 45 | textarea:active, 46 | textarea:focus{ 47 | cursor:text; 48 | outline:none; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_animations.scss: -------------------------------------------------------------------------------- 1 | 2 | [bs-anim~="spin"] { 3 | animation: spin 1s infinite linear; 4 | } 5 | 6 | @keyframes spin { 7 | from {transform:rotate(0deg);} 8 | to {transform:rotate(360deg);} 9 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_cloak.scss: -------------------------------------------------------------------------------- 1 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { 2 | display: none !important; 3 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_code.scss: -------------------------------------------------------------------------------- 1 | @import "../vars"; 2 | @import "../modules/mixins"; 3 | 4 | pre { 5 | margin-top: $half-spacing; 6 | padding: $half-spacing; 7 | border-radius: $base-radius; 8 | box-shadow: -10px 0px 10px $grey-border inset; 9 | border: 1px solid darken($grey-border, 2%); 10 | 11 | code { 12 | @include font-size(12px); 13 | @include font-size(16px); 14 | color: currentColor; 15 | line-height: 1; 16 | background: transparent; 17 | border: 0; 18 | } 19 | } 20 | 21 | code { 22 | background: $grey-bg; 23 | display: inline-block; 24 | padding: 0 5px; 25 | border: 1px solid $grey-border; 26 | color: darken($blue, 10%); 27 | @include font-size(14px); 28 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_custom-icons.scss: -------------------------------------------------------------------------------- 1 | .icon { 2 | display: inline-block; 3 | } 4 | 5 | .icon-trash { 6 | width: 100%; 7 | max-width: 26px; 8 | height: 26px; 9 | } 10 | 11 | .icon-word { 12 | 13 | width: 100%; 14 | max-width: 150px; 15 | height: 100%; 16 | margin-left: $gutter - 5px; 17 | color: $white; 18 | 19 | svg { 20 | position: relative; 21 | top: -1px; 22 | } 23 | } 24 | 25 | .icon-logo { 26 | 27 | color: $white; 28 | transition: all .1s; 29 | width: $icon-gutter; 30 | height: 37px; 31 | text-align: center; 32 | 33 | &:hover { 34 | color: $white; 35 | transform: scale(1.1); 36 | } 37 | } 38 | 39 | [bs-svg-icon] { 40 | display: inline-block; 41 | width: $base-spacing; 42 | height: $base-spacing; 43 | line-height: inherit; 44 | position: relative; 45 | top: $half-spacing/2; 46 | use { 47 | width: $base-spacing; 48 | height: $base-spacing; 49 | } 50 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_disconnect.scss: -------------------------------------------------------------------------------- 1 | @mixin cover-all { 2 | position: absolute; 3 | width: 100%; 4 | height: 100%; 5 | top: 0; 6 | left: 0; 7 | right: 0; 8 | } 9 | 10 | [bs-overlay] { 11 | 12 | @include cover-all; 13 | background: rgba(black, .9); 14 | padding: $base-spacing*2 $half-spacing; 15 | color: $white; 16 | text-align: center; 17 | visibility: hidden; 18 | z-index: 2000; 19 | 20 | &.active { 21 | visibility: visible; 22 | } 23 | 24 | * { 25 | color: $white; 26 | } 27 | 28 | [bs-svg-icon] { 29 | width: 40px; 30 | height: 40px; 31 | @include media-query(min, $lap-start) { 32 | width: 100px; 33 | height: 100px; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_grid.scss: -------------------------------------------------------------------------------- 1 | [bs-grid] { 2 | 3 | display: flex; 4 | width: 100%; 5 | flex-flow: wrap; 6 | 7 | > * { 8 | width: 100%; 9 | padding-top: $half-spacing; 10 | padding-bottom: $half-spacing/2; 11 | } 12 | } 13 | 14 | @include media-query(min, $desk-start) { 15 | [bs-grid~="desk-2"] { 16 | [bs-grid-item] { 17 | flex: 0 0 50%; 18 | } 19 | } 20 | } 21 | 22 | [bs-grid~="wide-4"] { 23 | [bs-grid-item] { 24 | @include media-query(min, $wide-start) { 25 | flex: 0 0 25%; 26 | } 27 | } 28 | } 29 | 30 | [bs-grid-item~="padded-right"] { 31 | @include media-query(min, $lap-start) { 32 | padding-right: $base-spacing*2; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_links.scss: -------------------------------------------------------------------------------- 1 | a { 2 | color: $link; 3 | transition: background 0.3s ease, color 0.3s ease; 4 | 5 | &:hover, 6 | &:active, 7 | &:focus{ 8 | // text-decoration:underline; 9 | color: $link-hover; 10 | } 11 | 12 | [class^="icon-"], 13 | [class*=" icon-"] { 14 | text-decoration: none; 15 | } 16 | } 17 | 18 | [bs-icon] { 19 | transition: background 0.3s ease, color 0.3s ease; 20 | } 21 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_main-content.scss: -------------------------------------------------------------------------------- 1 | @import "../vars"; 2 | @import "../modules/mixins"; 3 | 4 | [bs-container] { 5 | @include media-query(min, $lap-start) { 6 | display: flex; 7 | } 8 | } 9 | 10 | [bs-content] { 11 | 12 | overflow-x: hidden; 13 | height: auto; 14 | position: relative; 15 | background: $white; 16 | width: 100%; 17 | 18 | @include media-query(min, $lap-start) { 19 | height: 100vh; 20 | overflow-y: auto; 21 | -webkit-overflow-scrolling: touch; 22 | padding-bottom: 59px; // offset header from scroll 23 | margin-top: 1px; 24 | width: auto; 25 | flex: 1; 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_misc.scss: -------------------------------------------------------------------------------- 1 | hr { 2 | border-color: $grey-border; 3 | } 4 | 5 | code { 6 | 7 | color: $teal; 8 | } 9 | 10 | pre { 11 | 12 | overflow: auto; 13 | white-space: pre; 14 | white-space: pre-wrap; 15 | word-wrap: break-word; 16 | padding: $half-spacing/2 $half-spacing; 17 | color: $white; 18 | background: $navy; 19 | border-radius: $half-radius; 20 | 21 | code { 22 | color: $white; 23 | line-height: 1.25; 24 | } 25 | } 26 | 27 | [bs-stack] { 28 | margin-bottom: $half-spacing; 29 | } 30 | 31 | [bs-pointer~="default"] { 32 | cursor: pointer; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_msgs.scss: -------------------------------------------------------------------------------- 1 | %msg-line { 2 | padding-left: $base-spacing + $half-spacing; 3 | padding-top: 4px; 4 | padding-bottom: 4px; 5 | position: relative; 6 | } 7 | 8 | [bs-msg] { 9 | @extend %msg-line; 10 | } 11 | [bs-msg~="success"] { 12 | &:before { 13 | color: $lime; 14 | } 15 | } 16 | [bs-msg~="info"] { 17 | &:before { 18 | color: $yellow; 19 | } 20 | } 21 | [bs-msg~="error"] { 22 | &:before { 23 | color: $red; 24 | } 25 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_notifications.scss: -------------------------------------------------------------------------------- 1 | [bs-notify] { 2 | 3 | position: absolute; 4 | left: 0; 5 | width: 100%; 6 | background: $sidebar; 7 | color: $white; 8 | text-align: center; 9 | padding: $base-spacing $half-spacing; 10 | box-shadow: 0 5px 5px 0px rgba(0, 0, 0, .2); 11 | transform: translateY(-200%); 12 | transition: all .3s; 13 | z-index: 100; 14 | 15 | &.active { 16 | transform: translateY(0); 17 | } 18 | 19 | p { 20 | margin-bottom: 0; 21 | } 22 | 23 | &.success { 24 | 25 | } 26 | 27 | &.error { 28 | background: #ED6A13; 29 | } 30 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_paragraphs.scss: -------------------------------------------------------------------------------- 1 | .lede { 2 | // margin-bottom: $base-spacing; 3 | @include font-size($lede-size); 4 | } 5 | 6 | .small { 7 | @include font-size($small-size); 8 | } 9 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_sidebar.scss: -------------------------------------------------------------------------------- 1 | @import "../vars"; 2 | @import "../modules/mixins"; 3 | 4 | [bs-sidebar] { 5 | position: relative; 6 | 7 | @include sidebar-style; 8 | @include media-query(min, $lap-start) { 9 | width: $sidebar-width; 10 | 11 | &:after { 12 | content: " "; 13 | width: 10px; 14 | height: 100%; 15 | position: absolute; 16 | right: 0; 17 | top: 0; 18 | z-index: 10; 19 | background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%,rgba(black, .20) 100%); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_state.scss: -------------------------------------------------------------------------------- 1 | [bs-state~="success"] { 2 | opacity: 0; 3 | color: $lime; 4 | } 5 | 6 | [bs-state~="waiting"] { 7 | opacity: 0; 8 | color: $blue; 9 | } 10 | 11 | [bs-state-icons] { 12 | 13 | position: relative; 14 | 15 | [bs-svg-icon] { 16 | position: absolute; 17 | } 18 | } 19 | 20 | [bs-anim~="spin"] { 21 | animation: spin 1s infinite linear; 22 | } 23 | 24 | [bs-state-wrapper] { 25 | 26 | display: flex; 27 | 28 | [bs-state~="inline"] { 29 | top: 3px; 30 | left: $half-spacing; 31 | width: 17px; 32 | height: 27px; 33 | } 34 | 35 | &.waiting { 36 | [bs-state~="waiting"] { 37 | opacity: 1; 38 | } 39 | } 40 | &.success { 41 | [bs-state~="success"] { 42 | opacity: 1; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/scss/theme/_svg.scss: -------------------------------------------------------------------------------- 1 | svg { 2 | 3 | width: 100%; 4 | height: 100%; 5 | opacity: 1; 6 | fill: currentColor!important; 7 | transition: .3s; 8 | 9 | &.icon-hidden { 10 | opacity: 0; 11 | 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg-template.tmpl: -------------------------------------------------------------------------------- 1 | 2 | {#svg} 3 | 4 | {raw|s} 5 | {/svg}{~n} -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/bin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/block.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/circle-minus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/circle-ok.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/circle-pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/circle-play.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/circle-plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/imac.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/jh.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rectangle 1 + Rectangle 2 + Rectangle 3 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/newtab.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/pen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 10 | 11 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/plug.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/square-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/syncall.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/terminal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/src/svg/time.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/static/components/footer.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/static/components/heading.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | Server Info 5 |

6 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/static/components/panels.html: -------------------------------------------------------------------------------- 1 |
2 |

Page heading

3 |
4 |

5 | 6 | Overview 7 |

8 |
9 |
10 |
11 |

12 | 13 | Sync all 14 |

15 |
16 |
17 | 21 | 25 |
26 |
27 | 28 |
29 |

30 | 31 | Overview 32 |

33 |
34 |
35 | 36 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/tasks/crossbow.js: -------------------------------------------------------------------------------- 1 | var crossbow = require('crossbow-sites'); 2 | var vfs = require('vinyl-fs'); 3 | var resolve = require('path').resolve; 4 | 5 | const input = [ 6 | "src/crossbow/*.hbs", 7 | "src/crossbow/components/*.hbs", 8 | "src/crossbow/content/*.hbs", 9 | ]; 10 | 11 | vfs.src(input.map(x => resolve(x))) 12 | .pipe(crossbow.stream({ 13 | config: {base: "src/crossbow"}, 14 | data: {site: "file:_config.yml"}, 15 | })) 16 | .pipe(vfs.dest("./static")); 17 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/tasks/icons.js: -------------------------------------------------------------------------------- 1 | var easysvg = require("easy-svg"); 2 | var vfs = require("vinyl-fs"); 3 | 4 | /** 5 | * Compile SVG Symbols 6 | */ 7 | function icons (opts, ctx, done) { 8 | return vfs.src(opts.input) 9 | .pipe(easysvg.stream({js: false})) 10 | .on('error', done) 11 | .pipe(vfs.dest(opts.output)) 12 | } 13 | 14 | module.exports.tasks = [icons]; 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/templates/config.item.tmpl: -------------------------------------------------------------------------------- 1 | .when('%path%', { 2 | templateUrl: '%template%', 3 | controller: '%controller%', 4 | controllerAs: 'ctrl', 5 | resolve: { 6 | options: ['Options', function(opts) { 7 | return opts.all(); 8 | }] 9 | } 10 | }) -------------------------------------------------------------------------------- /packages/browser-sync-ui/templates/config.tmpl: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is generated automatically at run time by the Browsersync UI 3 | */ 4 | (function (angular) { 5 | 6 | angular.module("BrowserSync") 7 | 8 | .config(["$routeProvider", "$locationProvider", function ($routeProvider) { 9 | $routeProvider%when% 10 | }]) 11 | 12 | .value("pagesConfig", %pages%); 13 | 14 | })(angular); 15 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/templates/directives/bs-switch.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 11 | 12 |
13 |
14 |
15 |

{{item.title}}

16 |

{{item.tagline}}

17 |
18 |
19 |
20 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/templates/inline.template.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/templates/plugin.item.tmpl: -------------------------------------------------------------------------------- 1 | %content% -------------------------------------------------------------------------------- /packages/browser-sync-ui/templates/plugin.tmpl: -------------------------------------------------------------------------------- 1 | %markup% -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": "nofunc", 6 | "newcap": true, 7 | "noarg": true, 8 | "laxbreak": true, 9 | "sub": true, 10 | "undef": false, 11 | "unused": false, 12 | "quotmark": "double", 13 | "boss": true, 14 | "eqnull": true, 15 | "node": true, 16 | "validthis": true, 17 | "mocha": true, 18 | "globals": { 19 | "describe" : false, 20 | "it" : false, 21 | "expect" : false, 22 | "runs" : false, 23 | "waitsFor" : false, 24 | "beforeEach" : false, 25 | "afterEach" : false, 26 | "before" : false, 27 | "after" : false, 28 | "sinon" : false, 29 | "inject" : false, 30 | "assert" : false, 31 | "___browserSync___" : false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/client/e2e/bs-init.js: -------------------------------------------------------------------------------- 1 | module.exports = function (ptor, config) { 2 | 3 | var flow = ptor.promise.controlFlow(); 4 | var deferred = ptor.promise.defer(); 5 | 6 | var bs = require("browser-sync").create("Test Instance"); 7 | 8 | bs.use(require("../../../")); 9 | 10 | return flow.execute(function () { 11 | bs.init(config, function (err, _bs) { 12 | deferred.fulfill({ 13 | ui: _bs.ui, 14 | bs: _bs 15 | }); 16 | }); 17 | 18 | return deferred.promise; 19 | }); 20 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/client/e2e/config.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | seleniumAddress: "http://localhost:4444/wd/hub", 3 | specs: [process.argv.slice(4, 5)[0].replace("test/client/e2e/", "")] 4 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/client/e2e/e2e.plugins.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * E2E tests for the plugins page 4 | * 5 | */ 6 | var assert = require("chai").assert; 7 | 8 | describe('Plugins section', function() { 9 | 10 | var expected, selector, menu, bsUrl; 11 | var ptor = protractor.getInstance(); 12 | var url; 13 | 14 | beforeEach(function () { 15 | browser.ignoreSynchronization = true; 16 | browser.get("/plugins"); 17 | bsUrl = process.env["BS_URL"]; 18 | }); 19 | it("should list the form sync options", function () { 20 | expect(element.all(by.repeater("plugin in ui.plugins")).count()).toBe(1); 21 | }); 22 | }); -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/client/e2e/test-utils.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | openWindow: function (browser, url) { 3 | browser.executeScript("window.open('%s')".replace("%s", url)); 4 | } 5 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/forms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Narrow Jumbotron Template for Bootstrap 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-multi-templates/index.plugin.js: -------------------------------------------------------------------------------- 1 | const PLUGIN_NAME = "Test BS Plugin"; 2 | 3 | module.exports = { 4 | "plugin:name": PLUGIN_NAME, 5 | "plugin": function (opts, bs) { 6 | var logger = bs.getLogger(PLUGIN_NAME); 7 | bs.events.on("plugins:configure", function (data) { 8 | if (data.name === PLUGIN_NAME) { 9 | //console.log(data); 10 | } 11 | }); 12 | } 13 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-multi-templates/ui/client.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | const PLUGIN_NAME = "Test Plugin"; 4 | 5 | angular 6 | .module("BrowserSync") 7 | .directive("testPlugin", function () { 8 | return { 9 | restrict: "E", 10 | replace: true, 11 | scope: { 12 | "options": "=" 13 | }, 14 | templateUrl: "test.directive.html", 15 | controller: ["$scope", "Socket", function ($scope, Socket) { 16 | var ctrl = this; 17 | ctrl.removeRestriction = function (selector) { 18 | Socket.uiEvent({ 19 | namespace: PLUGIN_NAME, 20 | event: "remove", 21 | data: selector 22 | }); 23 | }; 24 | }], 25 | controllerAs: "ctrl" 26 | }; 27 | }); 28 | 29 | })(angular); 30 | 31 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-multi-templates/ui/client2.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | const PLUGIN_NAME = "Test Plugin file 2"; 4 | 5 | angular 6 | .module("BrowserSync") 7 | .directive("testPlugin", function () { 8 | return { 9 | restrict: "E", 10 | replace: true, 11 | scope: { 12 | "options": "=" 13 | }, 14 | templateUrl: "test.list.html", 15 | controller: ["$scope", "Socket", function ($scope, Socket) { 16 | var ctrl = this; 17 | ctrl.removeRestriction = function (selector) { 18 | Socket.uiEvent({ 19 | namespace: PLUGIN_NAME, 20 | event: "remove", 21 | data: selector 22 | }); 23 | }; 24 | }], 25 | controllerAs: "ctrl" 26 | }; 27 | }); 28 | 29 | })(angular); 30 | 31 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-multi-templates/ui/test.directive.html: -------------------------------------------------------------------------------- 1 |
2 |

Test markup from Test Directive

3 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-multi-templates/ui/test.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-multi-templates/ui/test.list.html: -------------------------------------------------------------------------------- 1 |
2 |

Test markup from Test LIST Directive

3 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-noui/index.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugin:name": "Test BS Plugin 2", 3 | "plugin": function () { 4 | console.log("Sup From the test plugin"); 5 | } 6 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin-noui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bs-test2-plugin", 3 | "version": "1.5.2", 4 | "description": "Fixture plugin", 5 | "main": "index.plugin.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/shakyshane/test-plugin.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/shakyshane/test-plugin/issues" 12 | }, 13 | "scripts": { 14 | "test": "mocha --reporter spec" 15 | }, 16 | "author": "", 17 | "license": "MIT", 18 | "devDependencies": { 19 | "browser-sync": "^2.3.1", 20 | "chai": "^1.9.1", 21 | "mocha": "^1.21.4", 22 | "multiline": "^0.3.4", 23 | "socket.io-client": "^1.1.0" 24 | }, 25 | "dependencies": { 26 | "dom-compare-temp": "^0.1.0", 27 | "jsdom": "^3.1.2", 28 | "lodash": "^2.4.1", 29 | "opt-merger": "^0.2.1", 30 | "debug": "^2.1.3", 31 | "request": "^2.40.0" 32 | }, 33 | "keywords": [ 34 | "browser sync plugin", 35 | "html injection" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin/index.plugin.js: -------------------------------------------------------------------------------- 1 | const PLUGIN_NAME = "Test BS Plugin"; 2 | 3 | module.exports = { 4 | "plugin:name": PLUGIN_NAME, 5 | "plugin": function (opts, bs) { 6 | var logger = bs.getLogger(PLUGIN_NAME); 7 | bs.events.on("plugins:configure", function (data) { 8 | if (data.name === PLUGIN_NAME) { 9 | //console.log(data); 10 | } 11 | }); 12 | } 13 | }; -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin/ui/client.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | const PLUGIN_NAME = "Test Plugin"; 4 | 5 | angular 6 | .module("BrowserSync") 7 | .directive("testPlugin", function () { 8 | return { 9 | restrict: "E", 10 | replace: true, 11 | scope: { 12 | "options": "=" 13 | }, 14 | templateUrl: "test.directive.html", 15 | controller: ["$scope", "Socket", function ($scope, Socket) { 16 | var ctrl = this; 17 | ctrl.removeRestriction = function (selector) { 18 | Socket.uiEvent({ 19 | namespace: PLUGIN_NAME, 20 | event: "remove", 21 | data: selector 22 | }); 23 | }; 24 | }], 25 | controllerAs: "ctrl" 26 | }; 27 | }); 28 | 29 | })(angular); 30 | 31 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin/ui/test.directive.html: -------------------------------------------------------------------------------- 1 |
2 |

Test markup from Test Directive

3 |
-------------------------------------------------------------------------------- /packages/browser-sync-ui/test/fixtures/plugin/ui/test.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/browser-sync-ui/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var config = { 3 | devtool: 'source-map', 4 | context: __dirname + '/src/scripts', 5 | entry: [ 6 | "./app.js" 7 | ], 8 | output: { 9 | path: __dirname + "/public", 10 | filename: "js/app.js" 11 | }, 12 | watchOptions: { 13 | poll: true 14 | } 15 | }; 16 | 17 | module.exports = config; 18 | -------------------------------------------------------------------------------- /packages/browser-sync/.gitignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | -------------------------------------------------------------------------------- /packages/browser-sync/.prettierignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/.prettierignore -------------------------------------------------------------------------------- /packages/browser-sync/certs/browsersync.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/certs/browsersync.pfx -------------------------------------------------------------------------------- /packages/browser-sync/certs/gen.sh: -------------------------------------------------------------------------------- 1 | openssl genrsa -des3 -out server.key 2048 2 | openssl req -new -key server.key -out server.csr 3 | openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt 4 | cp server.key server.key.copy 5 | openssl rsa -in server.key.copy -out server.key 6 | rm server.key.copy 7 | -------------------------------------------------------------------------------- /packages/browser-sync/certs/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICoTCCAYkCAQAwRTELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUx 3 | ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN 4 | AQEBBQADggEPADCCAQoCggEBAMRLR2crKB4X/9pM3gR641iDscZWW3aqo70nUDxz 5 | o5Bhk8uupqz0EfdRoCLCUeQixVp3HJ1HqnilMW7dETGGkDHKdxJRjrkBrYHhE3Kw 6 | /LCC4tEb400F6Ikm6OudVPIBP+CuwfNAw70KHSx/CtIrbTz0HhDC6XN0azp39pDL 7 | RBnWWluz3iU+rFLMx7YT2Q8k1nQAwcXkzLjeU7txAt2pYGQUgvBQETO5RI7QQ0Cm 8 | waV4gfHWGABBTX34WQun7g1QYukrG3/4fVeNLzGW787FKCvL07BTymJTwXXbTTPX 9 | g4chw9p+YkLLPrr+AOVe/PF1MJppDT3gKdKMHFo3vMycUf0CAwEAAaAXMBUGCSqG 10 | SIb3DQEJBzEIDAYxMjM0NTYwDQYJKoZIhvcNAQELBQADggEBABlVUaWK/UUovgPZ 11 | +rqNG8/j6aggSCCye9CkauLB/WqhQFfLl9lWTYdUVmWweNU0SJwDU9lWF/TngipF 12 | RZs6501DkXKxaDT9/3JYg4lRz6zHLy+a77pavJOeN0+cFAPZZuGyxZvYHFYPVSVH 13 | EeJL6bO/nZ/ARgIp0YNkQblDarxq1ARj7YT1Z24D5KgO1kQ55+fCY/wtct8TLGk9 14 | ujvWBbFEBSrJCDjRQeSctlP5qG8yfeJqZwZzo4PQMUwABhNLGUz0z0ceK8W1QnOm 15 | T+nCN5Fni04wO4dAZvYPp6wmU0Gpi2XBihbFl9CT3B5AmJmM8hQVpuQlmXeXT0FO 16 | pOZFpko= 17 | -----END CERTIFICATE REQUEST----- 18 | -------------------------------------------------------------------------------- /packages/browser-sync/cli-options/opts.init.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/browser-sync/cli-options/opts.recipe.json: -------------------------------------------------------------------------------- 1 | { 2 | "output": { 3 | "alias": "o", 4 | "desc": "Specify an output directory" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/browser-sync/cli-options/opts.reload.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "desc": "File paths to reload", 4 | "type": "array", 5 | "alias": "f" 6 | }, 7 | "port": { 8 | "alias": "p", 9 | "type": "number", 10 | "desc": "Target a running instance by port number" 11 | }, 12 | "url": { 13 | "alias": "u", 14 | "desc": "Provide the full the url to the running Browsersync instance" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/command.init.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var info = require("./cli-info"); 4 | 5 | /** 6 | * $ browser-sync init 7 | * 8 | * This command will generate a configuration 9 | * file in the current directory 10 | * 11 | * @param opts 12 | */ 13 | module.exports = function(opts) { 14 | info.makeConfig(process.cwd(), opts.cb); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/addCwdToWatchOptions.ts: -------------------------------------------------------------------------------- 1 | import { BsTempOptions, TransformResult } from "../cli-options"; 2 | 3 | export function addCwdToWatchOptions(incoming: BsTempOptions): TransformResult { 4 | const output = incoming.updateIn(["watchOptions", "cwd"], watchCwd => { 5 | return watchCwd || incoming.get("cwd"); 6 | }); 7 | 8 | return [output, []]; 9 | } 10 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/addDefaultIgnorePatterns.ts: -------------------------------------------------------------------------------- 1 | import { List } from "immutable"; 2 | import { BsTempOptions, TransformResult } from "../cli-options"; 3 | 4 | const defaultIgnorePatterns = [ 5 | /node_modules/, 6 | /bower_components/, 7 | ".sass-cache", 8 | ".vscode", 9 | ".git", 10 | ".idea" 11 | ]; 12 | 13 | export function addDefaultIgnorePatterns( 14 | incoming: BsTempOptions 15 | ): TransformResult { 16 | if (!incoming.get("watch")) { 17 | return [incoming, []]; 18 | } 19 | 20 | const output = incoming.update("watchOptions", watchOptions => { 21 | const userIgnored = List([]) 22 | .concat(watchOptions.get("ignored")) 23 | .filter(Boolean) 24 | .toSet(); 25 | 26 | const merged = userIgnored.merge(defaultIgnorePatterns); 27 | 28 | return watchOptions.merge({ 29 | ignored: merged.toList() 30 | }); 31 | }); 32 | 33 | return [output, []]; 34 | } 35 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/appendServerDirectoryOption.ts: -------------------------------------------------------------------------------- 1 | import { BsTempOptions, TransformResult } from "../cli-options"; 2 | 3 | export function appendServerDirectoryOption( 4 | incoming: BsTempOptions 5 | ): TransformResult { 6 | if (!incoming.get("server")) return [incoming, []]; 7 | if (incoming.get("directory")) { 8 | return [ 9 | incoming.setIn(["server", "directory"], incoming.has("directory")), 10 | [] 11 | ]; 12 | } 13 | return [incoming, []]; 14 | } 15 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/appendServerIndexOption.ts: -------------------------------------------------------------------------------- 1 | import { BsTempOptions, TransformResult } from "../cli-options"; 2 | 3 | export function appendServerIndexOption( 4 | incoming: BsTempOptions 5 | ): TransformResult { 6 | if (!incoming.get("server")) return [incoming, []]; 7 | const value = incoming.get("index"); 8 | 9 | if (value) { 10 | return [incoming.setIn(["server", "index"], value), []]; 11 | } 12 | 13 | return [incoming, []]; 14 | } 15 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/copyCLIIgnoreToWatchOptions.ts: -------------------------------------------------------------------------------- 1 | import { List } from "immutable"; 2 | import { BsTempOptions, TransformResult } from "../cli-options"; 3 | 4 | export function copyCLIIgnoreToWatchOptions( 5 | incoming: BsTempOptions 6 | ): TransformResult { 7 | if (!incoming.get("ignore")) { 8 | return [incoming, []]; 9 | } 10 | const output = incoming.updateIn( 11 | ["watchOptions", "ignored"], 12 | List([]), 13 | ignored => { 14 | return List([]).concat(ignored, incoming.get("ignore")); 15 | } 16 | ); 17 | 18 | return [output, []]; 19 | } 20 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/handleExtensionsOption.ts: -------------------------------------------------------------------------------- 1 | import { List } from "immutable"; 2 | import { 3 | BsTempOptions, 4 | explodeFilesArg, 5 | TransformResult 6 | } from "../cli-options"; 7 | 8 | const _ = require("../../lodash.custom"); 9 | 10 | export function handleExtensionsOption( 11 | incoming: BsTempOptions 12 | ): TransformResult { 13 | const value = incoming.get("extensions"); 14 | if (_.isString(value)) { 15 | const split = explodeFilesArg(value); 16 | if (split.length) { 17 | return [incoming.set("extensions", List(split)), []]; 18 | } 19 | } 20 | if (List.isList(value)) { 21 | return [incoming.set("extensions", value), []]; 22 | } 23 | return [incoming, []]; 24 | } 25 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/handleFilesOption.ts: -------------------------------------------------------------------------------- 1 | import { fromJS } from "immutable"; 2 | import { BsTempOptions, makeFilesArg, TransformResult } from "../cli-options"; 3 | import { FilesNamespaces } from "../../types"; 4 | 5 | export function handleFilesOption(incoming: BsTempOptions): TransformResult { 6 | const value = incoming.get("files"); 7 | const namespaces: FilesNamespaces = { 8 | core: { 9 | globs: [], 10 | objs: [] 11 | } 12 | }; 13 | 14 | const processed = makeFilesArg(value); 15 | 16 | if (processed.globs.length) { 17 | namespaces.core.globs = processed.globs; 18 | } 19 | 20 | if (processed.objs.length) { 21 | namespaces.core.objs = processed.objs; 22 | } 23 | 24 | return [incoming.set("files", fromJS(namespaces)), []]; 25 | } 26 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/cli/transforms/handlePortsOption.ts: -------------------------------------------------------------------------------- 1 | import { Map } from "immutable"; 2 | import { PortsOption } from "../../types"; 3 | import { BsTempOptions, TransformResult } from "../cli-options"; 4 | 5 | export function handlePortsOption(incoming: BsTempOptions): TransformResult { 6 | const value = incoming.get("ports"); 7 | if (!value) return [incoming, []]; 8 | 9 | const obj: PortsOption = { min: null, max: null }; 10 | 11 | if (typeof value === "string") { 12 | if (~value.indexOf(",")) { 13 | const segs = value.split(","); 14 | obj.min = parseInt(segs[0], 10); 15 | obj.max = parseInt(segs[1], 10); 16 | } else { 17 | obj.min = parseInt(value, 10); 18 | obj.max = null; 19 | } 20 | } else { 21 | obj.min = value.get("min"); 22 | obj.max = value.get("max") || null; 23 | } 24 | 25 | return [incoming.set("ports", Map(obj)), []]; 26 | } 27 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/public/exit.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * @param {BrowserSync} browserSync 5 | * @returns {Function} 6 | */ 7 | module.exports = function(browserSync) { 8 | function exit() { 9 | if (browserSync.active) { 10 | browserSync.events.emit("service:exit"); 11 | browserSync.cleanup(); 12 | } 13 | } 14 | 15 | return exit; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/public/notify.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * @param {BrowserSync} browserSync 5 | * @returns {Function} 6 | */ 7 | module.exports = function(browserSync) { 8 | return function(msg, timeout) { 9 | if (msg) { 10 | browserSync.events.emit("browser:notify", { 11 | message: msg, 12 | timeout: timeout || 2000, 13 | override: true 14 | }); 15 | } 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/public/pause.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * @param {BrowserSync} browserSync 5 | * @returns {Function} 6 | */ 7 | module.exports = function(browserSync) { 8 | return function() { 9 | browserSync.paused = true; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/public/resume.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * @param {BrowserSync} browserSync 5 | * @returns {Function} 6 | */ 7 | module.exports = function(browserSync) { 8 | return function() { 9 | browserSync.paused = false; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/server/serve-static-wrapper.ts: -------------------------------------------------------------------------------- 1 | export default function() { 2 | const serveStatic = require("serve-static"); 3 | 4 | /** 5 | * Adding a custom mime-type for wasm whilst we wait for 6 | * the `send` package to be updated. 7 | */ 8 | const send = require("send"); 9 | send.mime.define({ "application/wasm": ["wasm"] }); 10 | 11 | return serveStatic; 12 | } 13 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/server/snippet-server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var connect = require("connect"); 4 | var serverUtils = require("./utils.js"); 5 | 6 | /** 7 | * Create a server for the snippet 8 | * @param {BrowserSync} bs 9 | * @param scripts 10 | * @returns {*} 11 | */ 12 | module.exports = function createSnippetServer(bs, scripts) { 13 | var app = serverUtils.getBaseApp(bs, bs.options, scripts); 14 | return serverUtils.getServer(app, bs.options); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/browser-sync/lib/types.ts: -------------------------------------------------------------------------------- 1 | import * as url from "url"; 2 | import { Map } from "immutable"; 3 | 4 | export type ServerIncoming = string | string[] | IServerOption; 5 | 6 | export interface IServerOption { 7 | baseDir: string[]; 8 | index?: string; 9 | directory?: boolean; 10 | serveStaticOptions?: any; 11 | routes?: { [route: string]: string }; 12 | middleware?: MiddlewareInput; 13 | } 14 | 15 | export type MiddlewareInput = Function | Function[] | Middleware | Middleware[]; 16 | 17 | export interface Middleware { 18 | route: string; 19 | id?: string; 20 | handle: Function; 21 | } 22 | 23 | export type BrowsersyncProxyIncoming = string | BrowsersyncProxy; 24 | export interface BrowsersyncProxy { 25 | target: string; 26 | url: Map; 27 | middleware?: MiddlewareInput; 28 | } 29 | 30 | export type PortsOption = { 31 | min: number | null; 32 | max: number | null; 33 | }; 34 | 35 | export type FilesObject = { match: string[]; fn?: Function; options?: any }; 36 | export type FilesNamespace = { globs: string[]; objs: FilesObject[] }; 37 | export type FilesNamespaces = { [name: string]: FilesNamespace }; 38 | -------------------------------------------------------------------------------- /packages/browser-sync/templates/cli-template.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | |-------------------------------------------------------------------------- 4 | | Browser-sync config file 5 | |-------------------------------------------------------------------------- 6 | | 7 | | For up-to-date information about the options: 8 | | http://www.browsersync.io/docs/options/ 9 | | 10 | | There are more options than you see here, these are just the ones that are 11 | | set internally. See the website for more info. 12 | | 13 | | 14 | */ 15 | module.exports = //OPTS; -------------------------------------------------------------------------------- /packages/browser-sync/templates/connector.tmpl: -------------------------------------------------------------------------------- 1 | window.___browserSync___ = {}; 2 | ___browserSync___.socketConfig = %config%; 3 | ___browserSync___.socketUrl = %url%; 4 | ___browserSync___.options = %options%; 5 | if (location.protocol == "https:" && /^http:/.test(___browserSync___.socketUrl)) { 6 | ___browserSync___.socketUrl = ___browserSync___.socketUrl.replace(/^http:/, "https:"); 7 | } 8 | -------------------------------------------------------------------------------- /packages/browser-sync/templates/script-tags-simple.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/browser-sync/templates/script-tags.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /packages/browser-sync/test/env.js: -------------------------------------------------------------------------------- 1 | process.env.TESTING = true; 2 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/.tmp/temp.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: red; 3 | } -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/alt/index.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 |

Hello from the test

13 | Forms 14 | Scrolling Window 15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/assets/import.css: -------------------------------------------------------------------------------- 1 | @import "import2.css"; 2 | 3 | body { 4 | color: orange; 5 | } 6 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/assets/import2.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: red; 3 | } -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/assets/print.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #322323; 3 | } 4 | 5 | .container { 6 | margin: 0 auto; 7 | width: 320px; 8 | } -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: white; 3 | } 4 | 5 | 6 | .container { 7 | margin: 0 auto; 8 | width: 320px; 9 | } 10 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/bootstrap.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/bootstrap.html -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/bower.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |

Bower Components

12 | 13 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/bower_components/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: orange; 3 | } -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/config/si-config-partial.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | files: "test/fixtures/**/*.css", 3 | testConfig: true, 4 | server:false 5 | }; 6 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/config/si-config-ports.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | files: "test/fixtures/**/*.css", 3 | testConfig: true, 4 | logLevel: "info", 5 | background: false, 6 | reloadFileTypes: ['php', 'html', 'js', 'erb'], 7 | injectFileTypes: ['css', 'png', 'jpg', 'svg', 'gif'], 8 | host: null, 9 | ports: { 10 | min: 4000, 11 | max: 4004 12 | }, 13 | ghostMode: { 14 | links: true, 15 | forms: true, 16 | scroll: true 17 | }, 18 | server: { 19 | baseDir: "test/fixtures" 20 | }, 21 | open: true 22 | }; -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/config/si-config-proxy.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | files: "test/fixtures/**/*.css", 3 | testConfig: true, 4 | logLevel: "info", 5 | background: false, 6 | reloadFileTypes: ['php', 'html', 'js', 'erb'], 7 | injectFileTypes: ['css', 'png', 'jpg', 'svg', 'gif'], 8 | host: null, 9 | ghostMode: { 10 | links: true, 11 | forms: true, 12 | scroll: true 13 | }, 14 | proxy: { 15 | host: "192.168.0.4", 16 | port: "8000" 17 | }, 18 | open: true 19 | }; 20 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/config/si-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | files: ["test/fixtures/**/*.css", "test/fixtures/**/*.html"], 3 | testConfig: true, 4 | logLevel: "debug", 5 | open: false, 6 | server: { 7 | baseDir: "test/fixtures" 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/config/si-default-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | logLevel: "info", 3 | files: "test/fixtures/assets/style.css", 4 | background: false, 5 | defaultConfig: true, 6 | reloadFileTypes: ['php', 'html', 'js', 'erb'], 7 | injectFileTypes: ['css', 'png', 'jpg', 'svg', 'gif'], 8 | host: null, 9 | ghostMode: { 10 | links: false, 11 | forms: false, 12 | scroll: false 13 | }, 14 | server: false, 15 | open: true, 16 | notify: true 17 | }; -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/fonts/roboto/Roboto-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/fonts/roboto/Roboto-Regular-webfont.eot -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/fonts/roboto/Roboto-Regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/fonts/roboto/Roboto-Regular-webfont.ttf -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/fonts/roboto/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/fonts/roboto/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/fonts/roboto/stylesheet.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'robotoregular'; 3 | src: url('Roboto-Regular-webfont.eot'); 4 | src: url('Roboto-Regular-webfont.eot?#iefix') format('embedded-opentype'), 5 | url('Roboto-Regular-webfont.woff') format('woff'), 6 | url('Roboto-Regular-webfont.ttf') format('truetype'), 7 | url('Roboto-Regular-webfont.svg#robotoregular') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | 11 | } 12 | 13 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 | 13 |

Browsersync + iFrame

14 | Forms 15 | Scrolling Window 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/images.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page for images 8 | 9 | 10 | 11 | 12 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/img/cam-secure-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/img/cam-secure-02.png -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/img/cam-secure-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/img/cam-secure-03.png -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/img/cam-secure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/fixtures/img/cam-secure.png -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/import-link.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 |

With CSS imports

12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/import.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 11 | 12 | 13 |

With CSS imports

14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/index-amd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page (AMD) 8 | 9 | 10 | 11 | 12 | 13 | 14 |

Browsersync + Public URL

15 | Forms 16 | Scrolling Window 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/index-urls.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 | 13 |

Hello from the test Page

14 | Forms 15 | Scrolling Window 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 | 13 |

Browsersync + Public URL

14 | Forms 15 | 16 | Scrolling Window 17 | 18 |

Should rewrite

19 |

Should not rewrite

20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/js/default.js: -------------------------------------------------------------------------------- 1 | console.log('heelo'); 2 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/js/main.js: -------------------------------------------------------------------------------- 1 | define([], function () { 2 | console.log('hey!'); 3 | }); -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/less.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 |

Hello from the test

13 | Forms 14 | Scrolling Window 15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/links.html: -------------------------------------------------------------------------------- 1 | Link 2 | 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugin:name": "My Plugin", 3 | "plugin": function () { 4 | console.log('running here'); 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/proxy-headers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 | 13 |

Hello from the test Page

14 | Forms 15 | Scrolling Window 16 | 17 |

Click me

18 |

19 | 20 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/rewrites/comment.expected.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

This is an experiment.dev

4 |

5 | 6 |

Link

7 | 8 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/rewrites/comment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

This is an experiment.dev

4 |

5 | 6 |

Link

7 | 8 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/rewrites/escaped.1.expected.html: -------------------------------------------------------------------------------- 1 | 2 | phpdebugbar.setOpenHandler(new PhpDebugBar.OpenHandler({"url":"http:\/\/192.168.0.4:3002\/_debugbar\/open"})); 3 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/rewrites/escaped.1.html: -------------------------------------------------------------------------------- 1 | 2 | phpdebugbar.setOpenHandler(new PhpDebugBar.OpenHandler({"url":"http:\/\/demo.l5\/_debugbar\/open"})); 3 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/rewrites/hashes.expected.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/rewrites/hashes.input.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/sass.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test HTML Page 8 | 9 | 10 | 11 | 12 |

Hello from the test

13 | Forms 14 | Scrolling Window 15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/socket.io.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | About us 8 | 9 | 10 | 11 |
12 |

Browsersync + Socket IO

13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/svg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Included SVG reload test 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/svg/bin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/test.txt: -------------------------------------------------------------------------------- 1 | writing to file -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/test2.txt: -------------------------------------------------------------------------------- 1 | writing to file -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/username.github.io/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |

11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures/watch-func.txt: -------------------------------------------------------------------------------- 1 | A test generated this file and it is safe to delete changed -------------------------------------------------------------------------------- /packages/browser-sync/test/fixtures2/style-alt.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: green; 3 | } -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/bs.init.js: -------------------------------------------------------------------------------- 1 | 2 | var bs = require("../../"); 3 | 4 | module.exports = function (protractor, config) { 5 | var flow = protractor.promise.controlFlow(); 6 | var deferred = protractor.promise.defer(); 7 | return flow.execute(function () { 8 | bs.create().init(config, function (err, _bs) { 9 | deferred.fulfill(_bs); 10 | }); 11 | return deferred.promise; 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/config.multi.js: -------------------------------------------------------------------------------- 1 | 2 | exports.config = { 3 | seleniumAddress: "http://localhost:4444/wd/hub", 4 | baseUrl: process.env["BS_BASE"], 5 | specs: [ 6 | "tests/snippet.injection.js" 7 | ] 8 | }; 9 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/config.single.js: -------------------------------------------------------------------------------- 1 | 2 | exports.config = { 3 | seleniumAddress: "http://localhost:4444/wd/hub", 4 | specs: [ 5 | //process.env["BS_TEST_FILE"] 6 | //"tests/actions.clicks.js", 7 | "tests/actions.scroll.js", 8 | "tests/server.interactions.js", 9 | "tests/proxy.interactions.js", 10 | "tests/with.baseurl.js", 11 | "tests/with.baseurl.https.js" 12 | //"tests/with.socket.io.js" 13 | ] 14 | }; 15 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/logger.js: -------------------------------------------------------------------------------- 1 | var chalk = require("chalk"); 2 | module.exports = require("eazy-logger").Logger({ 3 | prefix: chalk.magenta("[BS E2E] "), 4 | useLevelPrefixes: true, 5 | custom: { 6 | "i": function (string) { 7 | return chalk.cyan(string) 8 | } 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/runProtractor.js: -------------------------------------------------------------------------------- 1 | 2 | var exec = require("child_process").exec; 3 | 4 | function runTests (config, configFile, cb) { 5 | var out = ""; 6 | exec("protractor " + configFile, function (err, stdout) { 7 | if (err) { 8 | doCallback({ 9 | code: 1, 10 | message: err.message ? err.message : stdout, 11 | stdout: stdout, 12 | err: err 13 | }); 14 | process.exit(1); 15 | } 16 | out += stdout; 17 | }).on("close", function (code) { 18 | if (code !== 0) { 19 | doCallback({ 20 | code: code, 21 | message: "Protractor tests failed, Details below" 22 | }, out); 23 | } else { 24 | doCallback(null, out); 25 | } 26 | }); 27 | 28 | function doCallback(err, out) { 29 | if (config.after) { 30 | config.after(function () { 31 | cb(err, out); 32 | }); 33 | } else { 34 | cb(err, out); 35 | } 36 | } 37 | } 38 | 39 | module.exports = runTests; 40 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/setup.js: -------------------------------------------------------------------------------- 1 | 2 | var eachSeries = require("async-each-series"); 3 | var path = require("path"); 4 | var logger = require("./logger"); 5 | var run = require("./_run")(logger); 6 | 7 | var tests = require("./tests.multi"); 8 | var configFile = path.resolve(__dirname + "/config.multi"); 9 | 10 | eachSeries(Object.keys(tests), function (item, asyncCallback) { 11 | logger.info("Running: {yellow:%s", item); 12 | process.env["BS_TEST_NAME"] = item; 13 | var bs = run(tests[item], configFile, function (err, out) { 14 | bs.cleanup(); 15 | if (out) { 16 | //console.log(out); 17 | } 18 | if (err) { 19 | return asyncCallback(err); 20 | } 21 | asyncCallback(); 22 | }); 23 | }, function (err) { 24 | if (err) { 25 | console.log(err.message); 26 | logger.error("Tests failed"); 27 | process.exit(1); 28 | } 29 | process.exit(0); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/tests.single.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = [ 3 | "actions.clicks.js", 4 | "actions.scroll.js", 5 | "server.interactions.js", 6 | "proxy.interactions.js", 7 | "with.socket.io.js" // PR coming 8 | ]; 9 | -------------------------------------------------------------------------------- /packages/browser-sync/test/protractor/utils.js: -------------------------------------------------------------------------------- 1 | 2 | var utils = require("../../dist/server/utils"); 3 | var connect = require("connect"); 4 | 5 | module.exports = { 6 | 7 | getApp: function getApp (options) { 8 | 9 | var html = "BrowsersyncBS"; 10 | var app = connect(); 11 | 12 | app.use("/", function (req, res) { 13 | res.setHeader("content-type", "text/html"); 14 | res.end(html); 15 | }); 16 | 17 | var appserver = utils.getServer(app, options); 18 | appserver.html = html; 19 | 20 | return appserver; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/api/init.active.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("API: .active - Retrieving the active state of browserSync", function() { 6 | before(function() { 7 | browserSync.reset(); 8 | }); 9 | 10 | it("should know the inactive state of BrowserSync", function() { 11 | assert.equal(browserSync.active, false); 12 | }); 13 | 14 | describe("Setting the active state", function() { 15 | var instance; 16 | 17 | before(function(done) { 18 | browserSync.reset(); 19 | var config = { 20 | logLevel: "silent", 21 | open: false 22 | }; 23 | 24 | instance = browserSync(config, function() { 25 | done(); 26 | }); 27 | }); 28 | 29 | after(function() { 30 | instance.cleanup(); 31 | }); 32 | 33 | it("should know the active State of BrowserSync", function() { 34 | assert.equal(browserSync.active, true); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/api/init.exit.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | var sinon = require("sinon"); 5 | 6 | describe("API: .exit() - Using the public exit method", function() { 7 | describe("should exit when BrowserSync is running.", function() { 8 | var instance; 9 | 10 | before(function(done) { 11 | browserSync.reset(); 12 | var config = { 13 | logLevel: "silent", 14 | open: false 15 | }; 16 | 17 | instance = browserSync(config, done); 18 | }); 19 | 20 | after(function() { 21 | instance.cleanup(); 22 | }); 23 | 24 | it("should know the active State of BrowserSync", function() { 25 | var stub = sinon.stub(process, "exit"); 26 | 27 | assert.equal(browserSync.active, true); 28 | 29 | browserSync.exit(); 30 | 31 | assert.equal(browserSync.active, false); 32 | 33 | stub.restore(); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/api/init.pause.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("API: .pause() / .resume() file reloading - ", function() { 6 | var bs; 7 | before(function(done) { 8 | browserSync.reset(); 9 | bs = browserSync( 10 | { 11 | logLevel: "silent" 12 | }, 13 | done 14 | ); 15 | }); 16 | after(function() { 17 | bs.cleanup(); 18 | }); 19 | 20 | it("should be unpaused", function() { 21 | assert.isFalse(browserSync.paused); 22 | }); 23 | 24 | it("should pause file reload:", function() { 25 | browserSync.pause(); 26 | assert.isTrue(browserSync.paused); 27 | }); 28 | 29 | it("should unpause file reload:", function() { 30 | browserSync.resume(); 31 | assert.isFalse(browserSync.paused); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/api/init.reload.deprecated.js: -------------------------------------------------------------------------------- 1 | var sinon = require("sinon"); 2 | var assert = require("chai").assert; 3 | 4 | describe("API: .reload() old signature", function() { 5 | delete require.cache[require.resolve("../../../")]; 6 | var browserSync = require("../../../"); 7 | 8 | var emitterStub, clock; 9 | 10 | before(function() { 11 | emitterStub = sinon.spy(browserSync.emitter, "emit"); 12 | clock = sinon.useFakeTimers(); 13 | }); 14 | 15 | afterEach(function() { 16 | emitterStub.reset(); 17 | clock.now = 0; 18 | }); 19 | 20 | after(function() { 21 | clock.restore(); 22 | emitterStub.restore(); 23 | }); 24 | 25 | it("should handle a reload call without running instance", function() { 26 | assert.doesNotThrow(function() { 27 | browserSync.reload({ stream: true }); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/api/init.returns.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/specs/api/init.returns.js -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/cli/cli.exec.js: -------------------------------------------------------------------------------- 1 | describe("CLI: exec", function() { 2 | this.timeout(10000); 3 | it("Can launch from cli", function(done) { 4 | var strem = require("child_process").spawn("node", [ 5 | require.resolve("../../../dist/bin"), 6 | "start" 7 | ]); 8 | var chunks = []; 9 | strem.stdout.on("data", function(data) { 10 | chunks.push(data.toString()); 11 | if (chunks.join("").indexOf("Copy the following snippet") > -1) { 12 | strem.kill("SIGINT"); 13 | } else { 14 | done(new Error("missing output")) 15 | } 16 | }); 17 | strem.on("close", function() { 18 | done(); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/cli/cli.get.config.js: -------------------------------------------------------------------------------- 1 | var info = require("../../../dist/cli/cli-info"); 2 | var assert = require("chai").assert; 3 | var path = require("path"); 4 | 5 | describe("When reading a config file from the file system", function() { 6 | it("should throw if the file is not found", function() { 7 | assert.throws(function() { 8 | info.getConfigFile("random/file/doesn'texist"); 9 | }); 10 | }); 11 | 12 | it("should not throw if the file is found", function() { 13 | assert.isDefined( 14 | info.getConfigFile("test/fixtures/config/si-config.js") 15 | ); 16 | }); 17 | 18 | it("should not throw if absolute path given", function() { 19 | var configPath = path.resolve("test/fixtures/config/si-config.js"); 20 | assert.isDefined(info.getConfigFile(configPath)); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/cli/cli.options.files.js: -------------------------------------------------------------------------------- 1 | var cli = require("../../../dist/cli/cli-options"); 2 | var merge = cli.merge; 3 | 4 | var assert = require("chai").assert; 5 | 6 | describe("CLI: Options: Merging Options: Files", function() { 7 | it("should return the files property from string given", function() { 8 | var [imm] = merge({ files: "css/*.css" }); 9 | assert.deepEqual( 10 | imm 11 | .get("files") 12 | .get("core") 13 | .toJS(), 14 | { 15 | globs: ["css/*.css"], 16 | objs: [] 17 | } 18 | ); 19 | }); 20 | it("should return the files property from array given", function() { 21 | var [imm] = merge({ files: ["css/*.css", "*.html"] }); 22 | assert.deepEqual( 23 | imm 24 | .get("files") 25 | .get("core") 26 | .toJS(), 27 | { 28 | globs: ["css/*.css", "*.html"], 29 | objs: [] 30 | } 31 | ); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/cli/cli.options.ignore.js: -------------------------------------------------------------------------------- 1 | var cli = require("../../../dist/cli/cli-options"); 2 | var merge = cli.merge; 3 | var assert = require("chai").assert; 4 | 5 | describe("CLI: Options: dealing with 'ignore' option", function() { 6 | it("watches in server mode (no files given)", function() { 7 | var cwd = "/Users/shakyshane/app"; 8 | var input = { 9 | server: true, 10 | files: ["**/*"], 11 | ignore: ["**/*.php"], 12 | cwd: cwd 13 | }; 14 | var config = merge(input)[0].toJS(); 15 | assert.deepEqual(config.files, { core: { globs: ["**/*"], objs: [] } }); 16 | assert.ok(config.watchOptions.ignored.indexOf("**/*.php") > -1); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/cli/cli.options.watchOptions.cwd.js: -------------------------------------------------------------------------------- 1 | var cli = require("../../../dist/cli/cli-options"); 2 | var merge = cli.merge; 3 | var assert = require("chai").assert; 4 | 5 | describe("ensures the CWD is transferred to the watchOptions.cwd ", function() { 6 | it("add cwd with files option", function() { 7 | var cwd = "/Users/shakyshane/app"; 8 | var input = { server: true, files: "**/*.html", cwd: cwd }; 9 | var config = merge(input)[0].toJS(); 10 | assert.deepEqual(config.watchOptions.cwd, "/Users/shakyshane/app"); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/e2e/cli/e2e.cli.init.js: -------------------------------------------------------------------------------- 1 | var assert = require("chai").assert; 2 | var fs = require("fs"); 3 | var path = require("path"); 4 | 5 | var pkg = require(path.resolve("package.json")); 6 | var cli = require(path.resolve(pkg.bin)).default; 7 | 8 | describe("E2E CLI init test", function() { 9 | before(function(done) { 10 | cli({ 11 | cli: { 12 | input: ["init"], 13 | flags: {} 14 | }, 15 | cb: done 16 | }); 17 | }); 18 | 19 | after(function(done) { 20 | fs.unlink("bs-config.js", done); 21 | }); 22 | 23 | it("creates a config file in cwd", function() { 24 | assert.equal(fs.existsSync("bs-config.js"), true); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/e2e/commands.server.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": [ 3 | { 4 | "desc": "Static file server using test/fixtures as the base", 5 | "args": [ 6 | "start", 7 | "--server=test/fixtures", 8 | "--no-open", 9 | "--logLevel=silent", 10 | "--no-online" 11 | ] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/e2e/e2e.options.script.async.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("E2E script with/without async attribute", function() { 6 | it("serves with async", function(done) { 7 | browserSync.reset(); 8 | var config = { open: false }; 9 | browserSync(config, function(err, bs) { 10 | assert.include(bs.options.get("snippet"), "async"); 11 | bs.cleanup(); 12 | done(); 13 | }); 14 | }); 15 | it("serves without async", function(done) { 16 | browserSync.reset(); 17 | var config = { 18 | open: false, 19 | snippetOptions: { 20 | async: false 21 | } 22 | }; 23 | browserSync(config, function(err, bs) { 24 | assert.notInclude(bs.options.get("snippet"), "'async'"); 25 | bs.cleanup(); 26 | done(); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/e2e/proxy/e2e.proxy.external.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../../"); 2 | 3 | var request = require("supertest"); 4 | var assert = require("chai").assert; 5 | 6 | describe.skip("E2E proxy test external", function() { 7 | var instance; 8 | 9 | before(function(done) { 10 | instance = browserSync( 11 | { 12 | proxy: "homestead.app:8000", 13 | open: false 14 | }, 15 | done 16 | ); 17 | }); 18 | 19 | after(function() { 20 | instance.cleanup(); 21 | }); 22 | 23 | it("can init proxy & serve a page", function(done) { 24 | assert.isString(instance.options.get("snippet")); 25 | assert.isDefined(instance.server); 26 | 27 | request(instance.server) 28 | .get("/") 29 | .set("accept", "text/html") 30 | .expect(200) 31 | .end(function(err, res) { 32 | assert.include(res.text, "browser-sync-client"); 33 | done(); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/instances/multi.emitter.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("E2E multi instance emitter access", function() { 6 | it("has access to the singleton emitter", function(done) { 7 | browserSync.reset(); 8 | 9 | browserSync({ logLevel: "silent" }, function() { 10 | assert.doesNotThrow(function() { 11 | browserSync.emitter.emit("some:event"); 12 | done(); 13 | }); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/instances/multi.get.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("E2E multi instance get", function() { 6 | it("throws an error when the instance does not exist", function() { 7 | browserSync.reset(); 8 | assert.throws(function() { 9 | browserSync.get("first").init(); 10 | }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/instances/multi.has.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("E2E multi instance has", function() { 6 | it("returns true if an instance exists", function() { 7 | browserSync.reset(); 8 | browserSync.create("ts"); 9 | assert.isTrue(browserSync.has("ts")); 10 | }); 11 | it("returns false if an instance does not exist", function() { 12 | browserSync.reset(); 13 | assert.isFalse(browserSync.has("ts")); 14 | browserSync.create("ts2"); 15 | assert.isTrue(browserSync.has("ts2")); 16 | assert.isFalse(browserSync.has("ts")); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/instances/multi.init.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("E2E multi instance init", function() { 6 | this.timeout(5000); 7 | 8 | var bs, config; 9 | 10 | before(function(done) { 11 | browserSync.reset(); 12 | 13 | config = { 14 | online: false, 15 | logLevel: "silent", 16 | open: false, 17 | server: "test/fixtures" 18 | }; 19 | 20 | bs = browserSync.create("first").init(config, done); 21 | }); 22 | 23 | after(function() { 24 | bs.cleanup(); 25 | }); 26 | 27 | it("returns an error when attempting to init same instance twice", function(done) { 28 | browserSync.get("first").init(config, function(err) { 29 | assert.isTrue(err instanceof Error); 30 | done(); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/plugins/bs.options.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("Plugins: Retrieving options via API", function() { 6 | it("has access to options", function(done) { 7 | browserSync.reset(); 8 | 9 | var config = { 10 | server: { 11 | baseDir: "test/fixtures" 12 | }, 13 | logLevel: "silent", 14 | open: false 15 | }; 16 | 17 | browserSync.use( 18 | { 19 | plugin: function(opts, bs) { 20 | assert.equal(opts.files, "*.css"); 21 | assert.ok(require("immutable").Map.isMap(bs.getOptions())); 22 | }, 23 | "plugin:name": "test" 24 | }, 25 | { files: "*.css" } 26 | ); 27 | 28 | browserSync(config, function(err, bs) { 29 | assert.equal(bs.watchers.test.watchers.length, 1); 30 | bs.cleanup(); 31 | done(); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/plugins/options.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | var BrowserSync = require("../../../dist/browser-sync"); 3 | 4 | var assert = require("chai").assert; 5 | 6 | describe("Plugins: Adding options:", function() { 7 | it("allows plugins to have access to options passed in '.use()'", function(done) { 8 | browserSync.reset(); 9 | 10 | var instance; 11 | 12 | var config = { 13 | server: { 14 | baseDir: "test/fixtures" 15 | }, 16 | logLevel: "silent", 17 | open: false 18 | }; 19 | 20 | browserSync.use( 21 | { 22 | plugin: function(opts, bs) { 23 | assert.equal(opts.name, "shane"); 24 | assert.isTrue(bs instanceof BrowserSync); 25 | instance.cleanup(); 26 | done(); 27 | }, 28 | "plugin:name": "test" 29 | }, 30 | { name: "shane" } 31 | ); 32 | 33 | instance = browserSync(config).instance; 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/plugins/ui.error.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | var assert = require("chai").assert; 3 | 4 | describe("Plugins: User interface with error on init", function() { 5 | it("Should start even when UI errors", function(done) { 6 | browserSync.reset(); 7 | browserSync.use({ 8 | "plugin:name": "UI", 9 | plugin: function(opts, bs, cb) { 10 | cb(new Error("Could not start")); 11 | } 12 | }); 13 | 14 | var config = { 15 | logLevel: "silent", 16 | server: "test/fixtures", 17 | open: false 18 | }; 19 | 20 | browserSync(config, function(err, bs) { 21 | assert.isUndefined(bs.ui); 22 | bs.cleanup(); 23 | done(); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/plugins/user.plugins.cleanup.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var sinon = require("sinon"); 4 | 5 | describe("Plugins: Allowing plugins to register cleanup tasks", function() { 6 | it("Should access to only the user-specified plugins", function(done) { 7 | var PLUGIN_NAME = "KITTENZ"; 8 | browserSync.reset(); 9 | var config = { 10 | logLevel: "silent", 11 | open: false 12 | }; 13 | var spy = sinon.spy(); 14 | 15 | browserSync.use({ 16 | plugin: function(opts, bs) { 17 | bs.registerCleanupTask(spy); 18 | }, 19 | "plugin:name": PLUGIN_NAME 20 | }); 21 | 22 | browserSync(config, function(err, bs) { 23 | bs.cleanup(); 24 | sinon.assert.calledOnce(spy); 25 | done(); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/plugins/user.plugins.inline.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("../../../"); 2 | 3 | var assert = require("chai").assert; 4 | 5 | describe("Plugins: Retrieving user plugins when given inline", function() { 6 | var instance; 7 | var PLUGIN_REQUIRE = "bs-snippet-injector"; 8 | var PLUGIN_NAME = "Snippet Injector"; 9 | 10 | before(function(done) { 11 | browserSync.reset(); 12 | 13 | var config = { 14 | logLevel: "silent", 15 | plugins: [PLUGIN_REQUIRE] 16 | }; 17 | 18 | instance = browserSync(config, done).instance; 19 | }); 20 | after(function() { 21 | instance.cleanup(); 22 | }); 23 | it("Should access to only the user-specified plugins (1)", function(done) { 24 | assert.equal(instance.getUserPlugins().length, 1); 25 | done(); 26 | }); 27 | it("Should access to only the user-specified plugins (2)", function(done) { 28 | var plugin = instance.getUserPlugins()[0]; 29 | assert.equal(plugin.name, PLUGIN_NAME); 30 | done(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/utils/utils.default.callback.js: -------------------------------------------------------------------------------- 1 | var utils = require("../../../dist/utils"); 2 | var assert = require("chai").assert; 3 | 4 | describe("Utils: default callback", function() { 5 | it("should log errors if no callback given", function() { 6 | var stub = require("sinon").stub(console, "error"); 7 | utils.defaultCallback(new Error("some error")); 8 | require("sinon").assert.called(stub); 9 | assert.equal(stub.getCall(0).args[0], "some error"); 10 | console.error.restore(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/utils/utils.fail.js: -------------------------------------------------------------------------------- 1 | var utils = require("../../../dist/utils"); 2 | var assert = require("chai").assert; 3 | 4 | describe("Utils: Failing", function() { 5 | it("should fail when Error obj given", function() { 6 | require("sinon").stub(process, "exit"); 7 | utils.fail(true, new Error("Some err bro"), function(out) { 8 | assert.instanceOf(out, Error); 9 | }); 10 | process.exit.restore(); 11 | }); 12 | it("should fail with Error obj when string given", function() { 13 | require("sinon").stub(process, "exit"); 14 | utils.fail(true, "Some err bro", function(out) { 15 | assert.instanceOf(out, Error); 16 | }); 17 | process.exit.restore(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/browser-sync/test/specs/utils/utils.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrowserSync/browser-sync/dc74bc0a6bcbe70eea5f2f94b524b2902436efb1/packages/browser-sync/test/specs/utils/utils.js -------------------------------------------------------------------------------- /tests/examples/snippet/snippet.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "@playwright/test"; 2 | import { makesRequestIn, test } from "../../utils"; 3 | 4 | test("Snippet works", async ({ page, bs }) => { 5 | await makesRequestIn(page, { 6 | matches: { pathname: "/browser-sync/socket.io/" }, 7 | when: { pageLoads: { url: bs.url } } 8 | }); 9 | }); 10 | 11 | test("Gives correct terminal output for file watching", async ({ page, bs }) => { 12 | await page.goto(bs.url); 13 | const prevCount = bs.stdout.length; 14 | await bs.touch("index.html"); 15 | const stdout = await bs.next({ stdout: { lines: { count: 1, after: prevCount } } }); 16 | expect(stdout).toContain("[Browsersync] Reloading Browsers...\n"); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/examples/tailwind/tailwind.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "@playwright/test"; 2 | import { test, responseFor } from "../../utils"; 3 | 4 | test("startup writes CSS file", async ({ page, bs }) => { 5 | const [body] = await responseFor({ 6 | pathname: "/dist/output.css", 7 | when: { page, loads: { url: bs.url } } 8 | }); 9 | expect(body).toContain(`! tailwindcss`); 10 | }); 11 | --------------------------------------------------------------------------------