1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-08-01 11:00:28 +02:00

Merge pull request #364 from chinchang/subdomain

render file preview iframe in subdomain
This commit is contained in:
Kushagra Gour
2019-02-28 18:30:14 +05:30
committed by GitHub
11 changed files with 1981 additions and 1722 deletions

View File

@@ -12,6 +12,7 @@ const child_process = require('child_process');
const merge = require('merge-stream');
const zip = require('gulp-zip');
var packageJson = JSON.parse(fs.readFileSync('./package.json'));
const connect = require('gulp-connect');
function minifyJs(fileName) {
const content = fs.readFileSync(fileName, 'utf8');
@@ -199,6 +200,14 @@ gulp.task('cleanup', function() {
return child_process.execSync('rm -rf build');
});
gulp.task('start-preview-server', function() {
connect.server({
root: 'preview',
port: 7888,
https: false
});
});
gulp.task('release', function(callback) {
runSequence(
'runWebpack',

View File

@@ -3,10 +3,10 @@
"version": "3.6.2",
"description": "A blazing fast & offline web playground",
"scripts": {
"start": "if-env NODE_ENV=production && npm run -s serve || npm run -s dev",
"start": "npm run -s dev && gulp start-preview-server",
"build": "preact build --template src/index.html --no-prerender --service-worker false",
"serve": "preact build && preact serve",
"dev": "preact watch --template src/index.html --https --no-prerender",
"dev": "preact watch --template src/index.html --no-prerender",
"lint": "eslint src",
"test": "jest",
"precommit": "lint-staged",
@@ -65,6 +65,7 @@
"copy-webpack-plugin": "^4.5.1",
"esprima": "^4.0.0",
"firebase": "^5.5.8",
"gulp-connect": "^5.7.0",
"jszip": "^3.1.5",
"preact": "^8.2.6",
"preact-compat": "^3.17.0",

1
preview/index.html Normal file
View File

@@ -0,0 +1 @@
Loading...

60
preview/service-worker.js Normal file
View File

@@ -0,0 +1,60 @@
const CACHE_NAME = 'webmaker-vfiles';
self.addEventListener('fetch', function(event) {
// console.log('fetch event', event.request.url, event.request);
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
return cache
.match(event.request)
.then(response => {
// console.log('responding with ', response);
if (response !== undefined) {
return response;
}
return fetch(event.request);
})
.catch(function(e) {
// Fall back to just fetch()ing the request if some unexpected error
// prevented the cached response from being valid.
console.warn(
'Couldn\'t serve response for "%s" from cache: %O',
event.request.url,
e
);
return fetch(event.request);
});
})
);
// }
});
function getContentType(url) {
if (url.match(/\.html$/)) {
return 'text/html; charset=UTF-8';
} else if (url.match(/\.css$/)) {
return 'text/css; charset=UTF-8';
} else if (url.match(/\.js$/)) {
return 'application/javascript; charset=UTF-8';
} else if (url.match(/\.json$/)) {
return 'application/json; charset=UTF-8';
}
return 'text/html; charset=UTF-8';
}
self.addEventListener('message', function(e) {
// console.log('message aya sw main', e.data);
caches.open(CACHE_NAME).then(function(cache) {
for (const url in e.data) {
if (Object.prototype.hasOwnProperty.call(e.data, url)) {
// console.log('Received data', url, e.data[url])
cache.put(
url,
new Response(e.data[url], {
headers: {
'Content-Type': getContentType(url)
}
})
);
}
}
});
});

52
preview/talk.html Normal file
View File

@@ -0,0 +1,52 @@
Hello
<script>
if (
'serviceWorker' in navigator
) {
// Delay registration until after the page has loaded, to ensure that our
// precaching requests don't degrade the first visit experience.
// See https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/registration
window.addEventListener('load', function () {
navigator.serviceWorker
.register('service-worker.js')
.then(function (reg) {
// updatefound is fired if service-worker.js changes.
reg.onupdatefound = function () {
// The updatefound event implies that reg.installing is set; see
// https://w3c.github.io/ServiceWorker/#service-worker-registration-updatefound-event
var installingWorker = reg.installing;
installingWorker.onstatechange = function () {
/* eslint-disable default-case */
switch (installingWorker.state) {
case 'installed':
console.log('New or updated content is available.');
break;
case 'redundant':
console.error(
'The installing service worker became redundant.'
);
break;
}
};
};
})
.catch(function (e) {
console.error('Error during service worker registration:', e);
});
});
}
</script>
<script>
console.log('controller', navigator.serviceWorker.controller)
window.addEventListener('message', (e) => {
console.log(88, e.data);
navigator.serviceWorker.controller.postMessage(e.data);
});
</script>

View File

@@ -244,8 +244,6 @@ export default class CodeEditor extends Component {
}
async initEditor() {
console.log('init editor');
this.editorReadyDeferred = deferred();
await this.loadDeps();

View File

@@ -69,6 +69,13 @@ export default class ContentWrap extends Component {
}
componentDidMount() {
this.props.onRef(this);
// Listen for logs from preview frame
window.addEventListener('message', e => {
if (e.data && e.data.logs) {
this.onMessageFromConsole(...e.data.logs);
}
});
}
onHtmlCodeChange(editor, change) {
@@ -160,7 +167,7 @@ export default class ContentWrap extends Component {
: `${location.origin}`;
var src = `filesystem:${origin}/temporary/preview.html`;
if (this.detachedWindow) {
this.detachedWindow.postMessage(src, '*');
this.detachedWindow.postMessage({ url: src }, '*');
} else {
this.frame.src = src;
}

View File

@@ -22,6 +22,9 @@ import { commandPaletteService } from '../commandPaletteService';
import { PreviewDimension } from './PreviewDimension';
const minCodeWrapSize = 33;
const PREVIEW_FRAME_HOST = window.DEBUG
? 'http://localhost:7888'
: `https://preview.${location.host}`;
/* global htmlCodeEl
*/
@@ -114,6 +117,13 @@ export default class ContentWrapFiles extends Component {
}
componentDidMount() {
this.props.onRef(this);
// Listen for logs from preview frame
window.addEventListener('message', e => {
if (e.data && e.data.logs) {
this.onMessageFromConsole(...e.data.logs);
}
});
this.commandPaletteSubscriptions = [];
this.commandPaletteSubscriptions.push(
commandPaletteService.subscribe(SWITCH_FILE_EVENT, file => {
@@ -226,7 +236,7 @@ export default class ContentWrapFiles extends Component {
);
// Namespace all file paths to '/user' because thats what the service worker
// recognizes.
const files = linearizeFiles(assignFilePaths(duplicateFiles, '/user'));
const files = linearizeFiles(assignFilePaths(duplicateFiles, ''));
files.forEach(file => {
obj[file.path] = file.content || '';
@@ -245,13 +255,19 @@ export default class ContentWrapFiles extends Component {
}
});
navigator.serviceWorker.controller.postMessage(obj);
// navigator.serviceWorker.controller.postMessage(obj);
window.talkFrame.contentWindow.postMessage(obj, '*');
if (this.detachedWindow) {
log('✉️ Sending message to detached window');
this.detachedWindow.postMessage({ contents: '/user/index.html' }, '*');
this.detachedWindow.postMessage(
{ url: `${PREVIEW_FRAME_HOST}/index.html` },
'*'
);
} else {
this.frame.src = '/user/index.html';
setTimeout(() => {
this.frame.src = `${PREVIEW_FRAME_HOST}/index.html`;
}, 10);
}
}
cleanupErrors() {
@@ -516,6 +532,38 @@ export default class ContentWrapFiles extends Component {
this.editor.focus();
}
detachPreview() {
if (this.detachedWindow) {
this.detachedWindow.focus();
return;
}
const iframeBounds = this.frame.getBoundingClientRect();
const iframeWidth = iframeBounds.width;
const iframeHeight = iframeBounds.height;
document.body.classList.add('is-detached-mode');
this.detachedWindow = window.open(
'./preview.html',
'Web Maker',
`width=${iframeWidth},height=${iframeHeight},resizable,scrollbars=yes,status=1`
);
// Trigger initial render in detached window
setTimeout(() => {
this.setPreviewContent(true);
}, 1500);
var intervalID = window.setInterval(checkWindow => {
if (this.detachedWindow && this.detachedWindow.closed) {
clearInterval(intervalID);
document.body.classList.remove('is-detached-mode');
this.detachedWindow = null;
// Update main frame preview to get latest changes (which were not
// getting reflected while detached window was open)
this.setPreviewContent(true);
}
}, 500);
}
onMessageFromConsole() {
const logs = [...arguments].map(arg => {
if (
@@ -570,7 +618,7 @@ export default class ContentWrapFiles extends Component {
this.onMessageFromConsole('> ' + e.target.value);
/* eslint-disable no-underscore-dangle */
this.frame.contentWindow._wmEvaluate(e.target.value);
this.frame.contentWindow.postMessage({ exprToEval: e.target.value }, '*');
/* eslint-enable no-underscore-dangle */
@@ -650,11 +698,12 @@ export default class ContentWrapFiles extends Component {
<div class="demo-side" id="js-demo-side" style="">
<iframe
ref={el => (this.frame = el)}
src="/user/index.html"
src={`${PREVIEW_FRAME_HOST}/index.html`}
frameborder="0"
id="demo-frame"
allowfullscreen
/>
<iframe src={`${PREVIEW_FRAME_HOST}/talk.html`} id="talkFrame" />
<PreviewDimension ref={comp => (this.previewDimension = comp)} />
<Console
logs={this.state.logs}
@@ -669,3 +718,4 @@ export default class ContentWrapFiles extends Component {
);
}
}
2;

View File

@@ -1,5 +1,5 @@
window.addEventListener('message', e => {
// Web app
// Recieving from app window
if (e.data && e.data.contents && e.data.contents.match(/<html/)) {
const frame = document.querySelector('iframe');
frame.src = frame.src;
@@ -8,8 +8,13 @@ window.addEventListener('message', e => {
frame.contentDocument.write(e.data.contents);
frame.contentDocument.close();
}, 10);
} else if (e.data && e.data.match(/preview\.html/)) {
// Chrome extension
document.querySelector('iframe').src = e.data;
}
if (e.data && e.data.url && e.data.match(/preview\.html/)) {
document.querySelector('iframe').src = e.data.url;
}
// Recieving from preview iframe
if (e.data && e.data.logs) {
window.opener.postMessage(e.data, '*');
}
});

View File

@@ -1,6 +1,28 @@
var mainWindow = window.parent.onMessageFromConsole
? window.parent
: window.parent.opener;
let mainWindow = window.parent;
function sanitizeDomNode(node) {
const fakeNode = {
nodeName: node.nodeName,
nodeType: node.nodeType,
tagName: node.tagName,
childNodes: [...node.childNodes].map(child => sanitizeDomNode(child)),
textContent: node.textContent
}
if(node.attributes) {
fakeNode.attributes = [...node.attributes].map(attribute => ({name:attribute.name, value:attribute.value}))
}
return fakeNode;
}
function sendLog(...args) {
const sanitizedArgs = [...args].map(arg => {
if(arg && arg instanceof HTMLElement) {
return sanitizeDomNode(arg)
}
return arg;
})
mainWindow.postMessage({ logs: sanitizedArgs },"*");
}
(function() {
var logEl,
isInitialized = false,
@@ -191,16 +213,21 @@ var mainWindow = window.parent.onMessageFromConsole
})();
screenLog.init({
noUi: true,
proxyCallback: function() {
mainWindow.onMessageFromConsole.apply(null, arguments);
proxyCallback: function(...args) {
sendLog(...args);
}
});
window._wmEvaluate = function _wmEvaluate(expr) {
try {
var result = eval(expr);
} catch (e) {
mainWindow.onMessageFromConsole.call(null, e);
sendLog(e.stack || e.message);
return;
}
mainWindow.onMessageFromConsole.call(null, result);
sendLog(result)
};
window.addEventListener('message', e => {
if(e.data && e.data.exprToEval) {
_wmEvaluate(e.data.exprToEval);
}
})

3449
yarn.lock

File diff suppressed because it is too large Load Diff