Skip to content

Commit

Permalink
Adding a delayed sim startup to wait for suitable conditions, see #764
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanolson committed Jun 27, 2019
1 parent b38f400 commit e40da9a
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 9 deletions.
20 changes: 14 additions & 6 deletions js/grunt/buildRunnable.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ module.exports = async function( repo, minifyOptions, instrument, allHTML, brand
const requireJS = await requireBuild( repo, `../${repo}/js/${repo}-config.js`, {
insertRequire: repo + '-main',
instrument: instrument,
brand: brand
brand: brand,
wrapPath: 'phet.chipper.runRequireJS'
} );

// Debug version is independent of passed in minifyOptions. PhET-iO brand is minified, but leaves assertions & logging.
Expand Down Expand Up @@ -141,7 +142,14 @@ module.exports = async function( repo, minifyOptions, instrument, allHTML, brand
'University of Colorado. Contact phethelp@colorado.edu regarding licensing.';
}

const chipperStringsScript = grunt.file.read( '../chipper/templates/chipper-strings.js' );
const stringsJS = grunt.file.read( '../chipper/templates/chipper-strings.js' );
const productionStringsJS = minify( stringsJS, minifyOptions );
const debugStringsJS = minify( stringsJS, debugMinifyOptions );

const startupJS = grunt.file.read( '../chipper/templates/chipper-startup.js' );
const productionStartupJS = minify( startupJS, minifyOptions );
const debugStartupJS = minify( startupJS, debugMinifyOptions );

const splashScript = `window.PHET_SPLASH_DATA_URI="${loadFileAsDataURI( `../brand/${brand}/images/splash.svg` )}";`;

grunt.log.ok( `Minification for ${brand} complete` );
Expand Down Expand Up @@ -176,7 +184,7 @@ module.exports = async function( repo, minifyOptions, instrument, allHTML, brand
stringMap: stringMap,
htmlHeader: htmlHeader,
locale: locale,
scripts: [ initializationScript, splashScript, mipmapsJavaScript, ...productionPreloads, chipperStringsScript, productionJS ]
scripts: [ initializationScript, splashScript, mipmapsJavaScript, ...productionPreloads, productionStringsJS, productionJS, productionStartupJS ]
} ) );
}
}
Expand All @@ -195,7 +203,7 @@ module.exports = async function( repo, minifyOptions, instrument, allHTML, brand
stringMap: stringMap,
htmlHeader: htmlHeader,
locale: ChipperConstants.FALLBACK_LOCALE,
scripts: [ initializationScript, splashScript, mipmapsJavaScript, ...productionPreloads, chipperStringsScript, productionJS ]
scripts: [ initializationScript, splashScript, mipmapsJavaScript, ...productionPreloads, productionStringsJS, productionJS, productionStartupJS ]
} );

grunt.file.write( allHTMLFilename, allHTMLContents );
Expand All @@ -214,7 +222,7 @@ module.exports = async function( repo, minifyOptions, instrument, allHTML, brand
stringMap: stringMap,
htmlHeader: htmlHeader,
locale: ChipperConstants.FALLBACK_LOCALE,
scripts: [ debugInitializationScript, splashScript, mipmapsJavaScript, ...debugPreloads, chipperStringsScript, debugJS ]
scripts: [ debugInitializationScript, splashScript, mipmapsJavaScript, ...debugPreloads, debugStringsJS, debugJS, debugStartupJS ]
} ) );

// XHTML build (ePub compatibility, etc.)
Expand All @@ -230,7 +238,7 @@ module.exports = async function( repo, minifyOptions, instrument, allHTML, brand
brand: brand,
stringMap: stringMap,
htmlHeader: htmlHeader,
scripts: [ xhtmlInitializationScript, splashScript, mipmapsJavaScript, ...productionPreloads, chipperStringsScript, productionJS ]
scripts: [ xhtmlInitializationScript, splashScript, mipmapsJavaScript, ...productionPreloads, productionStringsJS, productionJS, productionStartupJS ]
} );

// dependencies.json
Expand Down
2 changes: 1 addition & 1 deletion js/grunt/buildStandalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module.exports = async function( repo, minifyOptions ) {

const packageObject = grunt.file.readJSON( `../${repo}/package.json` );

const requireJS = await requireBuild( repo, `../${repo}/js/${repo}-config.js`, { wrap: false } );
const requireJS = await requireBuild( repo, `../${repo}/js/${repo}-config.js` );

const includedSources = [
'../assert/js/assert.js',
Expand Down
7 changes: 5 additions & 2 deletions js/grunt/requireBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const requirejs = require( 'requirejs' );
module.exports = function( repo, mainConfigFile, options ) {

const {
wrap = true,
wrapPath = null,
insertRequire = false,
instrument = false,
brand = 'phet'
Expand All @@ -53,7 +53,10 @@ module.exports = function( repo, mainConfigFile, options ) {

optimize: 'none',

wrap: wrap,
wrap: wrapPath ? {
start: 'phet.chipper.runRequireJS = function() {',
end: '};'
} : false,

// Avoid optimization names that are outside the baseUrl, see http://requirejs.org/docs/optimization.html#pitfalls
paths: {
Expand Down
89 changes: 89 additions & 0 deletions templates/chipper-startup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2019, University of Colorado Boulder

/*
* Delayed simulation/runnable startup so that we can ensure we are in an environment suitable for the sim to start up.
* See https://github.com/phetsims/chipper/issues/764 for more information.
*
* The require.js part is wrapped in a phet.chipper.runRequireJS() method.
*/

(function() {
'use strict';

// constants
const svgns = 'http://www.w3.org/2000/svg';

// Whether phet.chipper.runRequireJS has been called yet.
let started = false;

function isReady() {
// NOTE: We do NOT care about window.innerWidth/innerHeight. We can start up with those equal to 0, as long as our
// SVG bounds detection works. See https://github.com/phetsims/tasks/issues/1002.
if ( !document.body ) {
return false;
}

// Initialize the container and element, very similar in form to TextBounds.initializeTextBounds()

const container = document.createElementNS( svgns, 'svg' );
container.setAttribute( 'width', '2' );
container.setAttribute( 'height', '2' );
container.setAttribute( 'style', 'visibility: hidden; pointer-events: none; position: absolute; left: -65535px; right: -65535px;' );

const element = document.createElementNS( svgns, 'text' );
element.appendChild( document.createTextNode( '' ) );
element.setAttribute( 'dominant-baseline', 'alphabetic' ); // to match Canvas right now
element.setAttribute( 'text-rendering', 'geometricPrecision' );
element.setAttributeNS( 'http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve' );
container.appendChild( element );

document.body.appendChild( container );

// Equivalent setup to TextBounds.approximateSVGBounds
element.setAttribute( 'direction', 'ltr' );
element.setAttribute( 'font-family', 'Arial' );
element.setAttribute( 'font-size', 16 );
element.setAttribute( 'font-style', 'normal' );
element.setAttribute( 'font-weight', 'normal' );
element.setAttribute( 'font-stretch', 'normal' );
element.lastChild.nodeValue = 'm';

// Extract the measurement, and see if we have zero bounds.
const rect = element.getBBox();
const result = rect.width !== 0 || rect.height !== 0;

// Wait to remove the element until we've measured everything.
document.body.removeChild( container );

return result;
}

// We can call this anytime to attempt to start things (if they haven't been started already).
function attemptStart() {
if ( !started && isReady() ) {
started = true;

phet.chipper.runRequireJS();
}
}

// Attempt to start based on timeouts (in case other methods don't work). This will call attemptStart() at least once.
(function timeoutListener() {
attemptStart();

if ( !started ) {
setTimeout( timeoutListener, 1000 );
}
})();

if ( !started ) {
// Attempt to start on window resizes
window.addEventListener( 'resize', function resizeListener() {
attemptStart();

if ( started ) {
window.removeEventListener( 'resize', resizeListener );
}
} );
}
})();

0 comments on commit e40da9a

Please sign in to comment.