提交 6f6f40db 编写于 作者: R Rafael Almeida 提交者: JJ Kasper

Implement UI to show building activity (#6526)

* Initial version of build watcher working

* Move build watcher div to Main component

* Add a better design, remove container from DOM when not visible

* Fix flickering when closing and opening too fast

* Add a field on next config file for two styles and completely removal

* Ops, bring back fade-in animation

* Remove unnecessary commas

* Render building text by CSS, remove unnecessary jsx attribute

* Remove React usage

* Add support to IE/Edge

* Fix linter issues

* Set custom property with data attribute

* Use ondemand: 1 to don't override current listeners

* Use more strict rules to avoid outside CSS effects

* Use lighter box shadow

* Fix registering HMR callback

* Move initializing build watcher to client/next-dev

* Remove buildWatcherStyle and only use minimal

* Move build watcher element to render

* Move it to create element on initialize

* Fix type error from canary

* Remove extra log

* Simplify SVG markup
上级 3f91f80e
import { getEventSourceWrapper } from './dev-error-overlay/eventsource'
export default function initializeBuildWatcher () {
const host = document.createElement('div')
host.id = '__next-build-watcher'
document.body.appendChild(host)
const shadowHost = document.getElementById('__next-build-watcher')
if (!shadowHost) return
let shadowRoot
let prefix = ''
if (shadowHost.attachShadow) {
shadowRoot = shadowHost.attachShadow({ mode: 'open' })
} else {
// If attachShadow is undefined then the browser does not support
// the Shadow DOM, we need to prefix all the names so there
// will be no conflicts
shadowRoot = shadowHost
prefix = '__next-build-watcher-'
}
// Container
const container = createContainer(prefix)
shadowRoot.appendChild(container)
// CSS
const css = createCss(prefix)
shadowRoot.appendChild(css)
// State
let isVisible = false
let isBuilding = false
let timeoutId = null
// Handle events
const evtSource = getEventSourceWrapper({ path: '/_next/webpack-hmr' })
evtSource.addMessageListener((event) => {
// This is the heartbeat event
if (event.data === '\uD83D\uDC93') {
return
}
try {
handleMessage(event)
} catch { }
})
function handleMessage (event) {
const obj = JSON.parse(event.data)
switch (obj.action) {
case 'building':
timeoutId && clearTimeout(timeoutId)
isVisible = true
isBuilding = true
updateContainer()
break
case 'built':
isBuilding = false
// Wait for the fade out transtion to complete
timeoutId = setTimeout(() => {
isVisible = false
updateContainer()
}, 100)
updateContainer()
break
}
}
function updateContainer () {
if (isBuilding) {
container.classList.add(`${prefix}building`)
} else {
container.classList.remove(`${prefix}building`)
}
if (isVisible) {
container.classList.add(`${prefix}visible`)
} else {
container.classList.remove(`${prefix}visible`)
}
}
}
function createContainer (prefix) {
const container = document.createElement('div')
container.setAttribute('id', `${prefix}container`)
container.innerHTML = `
<div id="${prefix}icon-wrapper">
<svg viewBox="0 0 226 200">
<defs>
<linearGradient
x1="114.720775%"
y1="181.283245%"
x2="39.5399306%"
y2="100%"
id="${prefix}linear-gradient"
>
<stop stop-color="#FFFFFF" offset="0%" />
<stop stop-color="#000000" offset="100%" />
</linearGradient>
</defs>
<g id="${prefix}icon-group" fill="none" stroke="url(#${prefix}linear-gradient)" stroke-width="18">
<path d="M113,5.08219117 L4.28393801,197.5 L221.716062,197.5 L113,5.08219117 Z" />
</g>
</svg>
</div>
`
return container
}
function createCss (prefix) {
const css = document.createElement('style')
css.textContent = `
#${prefix}container {
position: absolute;
bottom: 10px;
right: 30px;
background: #fff;
color: #000;
font: initial;
cursor: initial;
letter-spacing: initial;
text-shadow: initial;
text-transform: initial;
visibility: initial;
padding: 8px 10px;
align-items: center;
box-shadow: 0 11px 40px 0 rgba(0, 0, 0, 0.25), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
display: none;
opacity: 0;
transition: opacity 0.1s ease, bottom 0.1s ease;
animation: ${prefix}fade-in 0.1s ease-in-out;
}
#${prefix}container.${prefix}visible {
display: flex;
}
#${prefix}container.${prefix}building {
bottom: 20px;
opacity: 1;
}
#${prefix}icon-wrapper {
width: 16px;
height: 16px;
}
#${prefix}icon-wrapper > svg {
width: 100%;
height: 100%;
}
#${prefix}icon-group {
animation: ${prefix}strokedash 1s ease-in-out both infinite;
}
@keyframes ${prefix}fade-in {
from {
bottom: 10px;
opacity: 0;
}
to {
bottom: 20px;
opacity: 1;
}
}
@keyframes ${prefix}strokedash {
0% {
stroke-dasharray: 0 226;
}
80%,
100% {
stroke-dasharray: 659 226;
}
}
`
return css
}
let hotDevCallback
const eventCallbacks = []
function EventSourceWrapper (options) {
var source
......@@ -33,8 +33,8 @@ function EventSourceWrapper (options) {
for (var i = 0; i < listeners.length; i++) {
listeners[i](event)
}
if (hotDevCallback && event.data.indexOf('action') !== -1) {
hotDevCallback(event)
if (event.data.indexOf('action') !== -1) {
eventCallbacks.forEach(cb => cb(event))
}
}
......@@ -59,7 +59,7 @@ export function getEventSourceWrapper (options) {
if (!options.ondemand) {
return {
addMessageListener: cb => {
hotDevCallback = cb
eventCallbacks.push(cb)
}
}
}
......
......@@ -76,7 +76,7 @@ export const emitter = mitt()
export default async ({
webpackHMR: passedWebpackHMR
} = {}) => {
// This makes sure this specific line is removed in production
// This makes sure this specific lines are removed in production
if (process.env.NODE_ENV === 'development') {
webpackHMR = passedWebpackHMR
}
......
......@@ -2,6 +2,7 @@ import initNext, * as next from './'
import EventSourcePolyfill from './event-source-polyfill'
import initOnDemandEntries from './on-demand-entries-client'
import initWebpackHMR from './webpack-hot-middleware-client'
import initializeBuildWatcher from './dev-build-watcher'
// Temporary workaround for the issue described here:
// https://github.com/zeit/next.js/issues/3775#issuecomment-407438123
......@@ -27,6 +28,7 @@ window.next = next
initNext({ webpackHMR })
.then((emitter) => {
initOnDemandEntries({ assetPrefix: prefix })
initializeBuildWatcher()
let lastScroll
......
......@@ -371,7 +371,11 @@ export class Main extends Component {
render() {
const { amphtml, html } = this.context._documentProps
if (amphtml) return '__NEXT_AMP_RENDER_TARGET__'
return <div id="__next" dangerouslySetInnerHTML={{ __html: html }} />
return (
<>
<div id="__next" dangerouslySetInnerHTML={{ __html: html }} />
</>
)
}
}
......
......@@ -11,6 +11,7 @@ const statusCodes: { [code: number]: string } = {
export type ErrorProps = {
statusCode: number,
title: string,
}
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册