Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e7953b3b
Unverified
Commit
e7953b3b
authored
Feb 11, 2021
by
Yegor
Committed by
GitHub
Feb 11, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[web] new service worker loading mechanism (#75535)
parent
78ce11d7
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
491 additions
and
140 deletions
+491
-140
browser.dart
dev/bots/browser.dart
+54
-0
service_worker_test.dart
dev/bots/service_worker_test.dart
+240
-116
test.dart
dev/bots/test.dart
+2
-0
browser.dart
dev/devicelab/lib/framework/browser.dart
+4
-0
index.html
dev/integration_tests/flutter_gallery/web/index.html
+59
-3
service_worker_test.dart
dev/integration_tests/web/lib/service_worker_test.dart
+4
-12
index.html
dev/integration_tests/web/web/index.html
+62
-2
web.dart
packages/flutter_tools/lib/src/build_system/targets/web.dart
+7
-1
index.html.tmpl
packages/flutter_tools/templates/app/web/index.html.tmpl
+59
-6
No files found.
dev/bots/browser.dart
View file @
e7953b3b
...
...
@@ -57,3 +57,57 @@ Future<String> evalTestAppInChrome({
await
server
?.
close
();
}
}
typedef
ServerRequestListener
=
void
Function
(
Request
);
class
AppServer
{
AppServer
.
_
(
this
.
_server
,
this
.
chrome
,
this
.
onChromeError
);
static
Future
<
AppServer
>
start
({
@required
String
appUrl
,
@required
String
appDirectory
,
@required
String
cacheControl
,
int
serverPort
=
8080
,
int
browserDebugPort
=
8081
,
bool
headless
=
true
,
List
<
Handler
>
additionalRequestHandlers
,
})
async
{
io
.
HttpServer
server
;
Chrome
chrome
;
server
=
await
io
.
HttpServer
.
bind
(
'localhost'
,
serverPort
);
final
Handler
staticHandler
=
createStaticHandler
(
appDirectory
,
defaultDocument:
'index.html'
);
Cascade
cascade
=
Cascade
();
if
(
additionalRequestHandlers
!=
null
)
{
for
(
final
Handler
handler
in
additionalRequestHandlers
)
{
cascade
=
cascade
.
add
(
handler
);
}
}
cascade
=
cascade
.
add
((
Request
request
)
async
{
final
Response
response
=
await
staticHandler
(
request
);
return
response
.
change
(
headers:
<
String
,
Object
>{
'cache-control'
:
cacheControl
,
});
});
shelf_io
.
serveRequests
(
server
,
cascade
.
handler
);
final
io
.
Directory
userDataDirectory
=
io
.
Directory
.
systemTemp
.
createTempSync
(
'chrome_user_data_'
);
final
Completer
<
String
>
chromeErrorCompleter
=
Completer
<
String
>();
chrome
=
await
Chrome
.
launch
(
ChromeOptions
(
headless:
headless
,
debugPort:
browserDebugPort
,
url:
appUrl
,
userDataDirectory:
userDataDirectory
.
path
,
windowHeight:
1024
,
windowWidth:
1024
,
),
onError:
chromeErrorCompleter
.
complete
);
return
AppServer
.
_
(
server
,
chrome
,
chromeErrorCompleter
.
future
);
}
final
Future
<
String
>
onChromeError
;
final
io
.
HttpServer
_server
;
final
Chrome
chrome
;
Future
<
void
>
stop
()
async
{
chrome
?.
stop
();
await
_server
?.
close
();
}
}
dev/bots/service_worker_test.dart
View file @
e7953b3b
This diff is collapsed.
Click to expand it.
dev/bots/test.dart
View file @
e7953b3b
...
...
@@ -15,6 +15,7 @@ import 'package:path/path.dart' as path;
import
'browser.dart'
;
import
'flutter_compact_formatter.dart'
;
import
'run_command.dart'
;
import
'service_worker_test.dart'
;
import
'utils.dart'
;
typedef
ShardRunner
=
Future
<
void
>
Function
();
...
...
@@ -811,6 +812,7 @@ Future<void> _runWebLongRunningTests() async {
()
=>
_runGalleryE2eWebTest
(
'profile'
,
canvasKit:
true
),
()
=>
_runGalleryE2eWebTest
(
'release'
),
()
=>
_runGalleryE2eWebTest
(
'release'
,
canvasKit:
true
),
()
=>
runWebServiceWorkerTest
(
headless:
true
),
];
await
_ensureChromeDriverIsRunning
();
await
_runShardRunnerIndexOfTotalSubshard
(
tests
);
...
...
dev/devicelab/lib/framework/browser.dart
View file @
e7953b3b
...
...
@@ -196,6 +196,10 @@ class Chrome {
return
data
;
}
Future
<
void
>
reloadPage
({
bool
ignoreCache
=
false
})
async
{
await
_debugConnection
.
page
.
reload
(
ignoreCache:
ignoreCache
);
}
/// Stops the Chrome process.
void
stop
()
{
_isStopped
=
true
;
...
...
dev/integration_tests/flutter_gallery/web/index.html
View file @
e7953b3b
...
...
@@ -23,12 +23,68 @@ found in the LICENSE file. -->
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var
serviceWorkerVersion
=
null
;
var
scriptLoaded
=
false
;
function
loadMainDartJs
()
{
if
(
scriptLoaded
)
{
return
;
}
scriptLoaded
=
true
;
var
scriptTag
=
document
.
createElement
(
'script'
);
scriptTag
.
src
=
'main.dart.js'
;
scriptTag
.
type
=
'application/javascript'
;
document
.
body
.
append
(
scriptTag
);
}
if
(
'serviceWorker'
in
navigator
)
{
window
.
addEventListener
(
'flutter-first-frame'
,
function
()
{
navigator
.
serviceWorker
.
register
(
'flutter_service_worker.js'
);
// Service workers are supported. Use them.
window
.
addEventListener
(
'load'
,
function
()
{
// Wait for registration to finish before dropping the
<
script
>
tag
.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var
serviceWorkerUrl
=
'flutter_service_worker.js?v='
+
serviceWorkerVersion
;
navigator
.
serviceWorker
.
register
(
serviceWorkerUrl
)
.
then
((
reg
)
=>
{
function
waitForActivation
(
serviceWorker
)
{
serviceWorker
.
addEventListener
(
'statechange'
,
()
=>
{
if
(
serviceWorker
.
state
==
'activated'
)
{
console
.
log
(
'Installed new service worker.'
);
loadMainDartJs
();
}
});
}
if
(
!
reg
.
active
&&
(
reg
.
installing
||
reg
.
waiting
))
{
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation
(
reg
.
installing
??
reg
.
waiting
);
}
else
if
(
!
reg
.
active
.
scriptURL
.
endsWith
(
serviceWorkerVersion
))
{
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console
.
log
(
'New service worker available.'
);
reg
.
update
();
waitForActivation
(
reg
.
installing
);
}
else
{
// Existing service worker is still good.
console
.
log
(
'Loading app from service worker.'
);
loadMainDartJs
();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint
<
script
>
tag
.
setTimeout
(()
=>
{
if
(
!
scriptLoaded
)
{
console
.
warn
(
'Failed to load app from service worker. Falling back to plain <script> tag.'
,
);
loadMainDartJs
();
}
},
4000
);
});
}
else
{
// Service workers not supported. Just drop the
<
script
>
tag
.
loadMainDartJs
();
}
</script>
<script
src=
"main.dart.js"
type=
"application/javascript"
></script>
</body>
</html>
dev/integration_tests/web/lib/service_worker_test.dart
View file @
e7953b3b
...
...
@@ -4,16 +4,8 @@
import
'dart:html'
as
html
;
Future
<
void
>
main
()
async
{
final
html
.
ServiceWorkerRegistration
worker
=
await
html
.
window
.
navigator
.
serviceWorker
.
ready
;
if
(
worker
.
active
!=
null
)
{
await
Future
.
delayed
(
const
Duration
(
seconds:
5
));
await
html
.
HttpRequest
.
getString
(
'CLOSE'
);
return
;
}
worker
.
addEventListener
(
'statechange'
,
(
event
)
async
{
if
(
worker
.
active
!=
null
)
{
await
Future
.
delayed
(
const
Duration
(
seconds:
5
));
await
html
.
HttpRequest
.
getString
(
'CLOSE'
);
}
});
await
html
.
window
.
navigator
.
serviceWorker
.
ready
;
final
String
response
=
'CLOSE?version=1'
;
await
html
.
HttpRequest
.
getString
(
response
);
html
.
document
.
body
.
appendHtml
(
response
);
}
dev/integration_tests/web/web/index.html
View file @
e7953b3b
...
...
@@ -8,6 +8,10 @@ found in the LICENSE file. -->
<meta
content=
"IE=Edge"
http-equiv=
"X-UA-Compatible"
>
<title>
Web Test
</title>
<!-- iOS meta tags & icons -->
<meta
name=
"apple-mobile-web-app-capable"
content=
"yes"
>
<meta
name=
"apple-mobile-web-app-status-bar-style"
content=
"black"
>
<meta
name=
"apple-mobile-web-app-title"
content=
"Web Test"
>
<link
rel=
"manifest"
href=
"manifest.json"
>
</head>
<body>
...
...
@@ -15,12 +19,68 @@ found in the LICENSE file. -->
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var
serviceWorkerVersion
=
null
;
var
scriptLoaded
=
false
;
function
loadMainDartJs
()
{
if
(
scriptLoaded
)
{
return
;
}
scriptLoaded
=
true
;
var
scriptTag
=
document
.
createElement
(
'script'
);
scriptTag
.
src
=
'main.dart.js'
;
scriptTag
.
type
=
'application/javascript'
;
document
.
body
.
append
(
scriptTag
);
}
if
(
'serviceWorker'
in
navigator
)
{
// Service workers are supported. Use them.
window
.
addEventListener
(
'load'
,
function
()
{
navigator
.
serviceWorker
.
register
(
'flutter_service_worker.js'
);
// Wait for registration to finish before dropping the
<
script
>
tag
.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var
serviceWorkerUrl
=
'flutter_service_worker.js?v='
+
serviceWorkerVersion
;
navigator
.
serviceWorker
.
register
(
serviceWorkerUrl
)
.
then
((
reg
)
=>
{
function
waitForActivation
(
serviceWorker
)
{
serviceWorker
.
addEventListener
(
'statechange'
,
()
=>
{
if
(
serviceWorker
.
state
==
'activated'
)
{
console
.
log
(
'Installed new service worker.'
);
loadMainDartJs
();
}
});
}
if
(
!
reg
.
active
&&
(
reg
.
installing
||
reg
.
waiting
))
{
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation
(
reg
.
installing
??
reg
.
waiting
);
}
else
if
(
!
reg
.
active
.
scriptURL
.
endsWith
(
serviceWorkerVersion
))
{
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console
.
log
(
'New service worker available.'
);
reg
.
update
();
waitForActivation
(
reg
.
installing
);
}
else
{
// Existing service worker is still good.
console
.
log
(
'Loading app from service worker.'
);
loadMainDartJs
();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint
<
script
>
tag
.
setTimeout
(()
=>
{
if
(
!
scriptLoaded
)
{
console
.
warn
(
'Failed to load app from service worker. Falling back to plain <script> tag.'
,
);
loadMainDartJs
();
}
},
4000
);
});
}
else
{
// Service workers not supported. Just drop the
<
script
>
tag
.
loadMainDartJs
();
}
</script>
<script
src=
"main.dart.js"
type=
"application/javascript"
></script>
</body>
</html>
packages/flutter_tools/lib/src/build_system/targets/web.dart
View file @
e7953b3b
...
...
@@ -356,6 +356,12 @@ class WebReleaseBundle extends Target {
if
(
environment
.
fileSystem
.
path
.
basename
(
inputFile
.
path
)
==
'index.html'
)
{
final
String
randomHash
=
Random
().
nextInt
(
4294967296
).
toString
();
final
String
resultString
=
inputFile
.
readAsStringSync
()
.
replaceFirst
(
'var serviceWorkerVersion = null'
,
"var serviceWorkerVersion = '
$randomHash
'"
,
)
// This is for legacy index.html that still use the old service
// worker loading mechanism.
.
replaceFirst
(
"navigator.serviceWorker.register('flutter_service_worker.js')"
,
"navigator.serviceWorker.register('flutter_service_worker.js?v=
$randomHash
')"
,
...
...
@@ -492,7 +498,7 @@ self.addEventListener("install", (event) => {
return
event
.
waitUntil
(
caches
.
open
(
TEMP
).
then
((
cache
)
=>
{
return
cache
.
addAll
(
CORE
.
map
((
value
)
=>
new
Request
(
value
+
'?revision='
+
RESOURCES
[
value
]
,
{
'cache'
:
'reload'
})));
CORE
.
map
((
value
)
=>
new
Request
(
value
,
{
'cache'
:
'reload'
})));
})
);
});
...
...
packages/flutter_tools/templates/app/web/index.html.tmpl
View file @
e7953b3b
...
...
@@ -23,9 +23,6 @@
<meta
name=
"apple-mobile-web-app-title"
content=
"{{projectName}}"
>
<link
rel=
"apple-touch-icon"
href=
"icons/Icon-192.png"
>
<!-- Favicon -->
<link
rel=
"icon"
type=
"image/png"
href=
"favicon.png"
/>
<title>
{{projectName}}
</title>
<link
rel=
"manifest"
href=
"manifest.json"
>
</head>
...
...
@@ -34,12 +31,68 @@
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var
serviceWorkerVersion
=
null
;
var
scriptLoaded
=
false
;
function
loadMainDartJs
()
{
if
(
scriptLoaded
)
{
return
;
}
scriptLoaded
=
true
;
var
scriptTag
=
document
.
createElement
(
'script'
);
scriptTag
.
src
=
'main.dart.js'
;
scriptTag
.
type
=
'application/javascript'
;
document
.
body
.
append
(
scriptTag
);
}
if
(
'serviceWorker'
in
navigator
)
{
window
.
addEventListener
(
'flutter-first-frame'
,
function
()
{
navigator
.
serviceWorker
.
register
(
'flutter_service_worker.js'
);
// Service workers are supported. Use them.
window
.
addEventListener
(
'load'
,
function
()
{
// Wait for registration to finish before dropping the
<
script
>
tag
.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var
serviceWorkerUrl
=
'flutter_service_worker.js?v='
+
serviceWorkerVersion
;
navigator
.
serviceWorker
.
register
(
serviceWorkerUrl
)
.
then
((
reg
)
=>
{
function
waitForActivation
(
serviceWorker
)
{
serviceWorker
.
addEventListener
(
'statechange'
,
()
=>
{
if
(
serviceWorker
.
state
==
'activated'
)
{
console
.
log
(
'Installed new service worker.'
);
loadMainDartJs
();
}
});
}
if
(
!
reg
.
active
&&
(
reg
.
installing
||
reg
.
waiting
))
{
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation
(
reg
.
installing
??
reg
.
waiting
);
}
else
if
(
!
reg
.
active
.
scriptURL
.
endsWith
(
serviceWorkerVersion
))
{
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console
.
log
(
'New service worker available.'
);
reg
.
update
();
waitForActivation
(
reg
.
installing
);
}
else
{
// Existing service worker is still good.
console
.
log
(
'Loading app from service worker.'
);
loadMainDartJs
();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint
<
script
>
tag
.
setTimeout
(()
=>
{
if
(
!
scriptLoaded
)
{
console
.
warn
(
'Failed to load app from service worker. Falling back to plain <script> tag.'
,
);
loadMainDartJs
();
}
},
4000
);
});
}
else
{
// Service workers not supported. Just drop the
<
script
>
tag
.
loadMainDartJs
();
}
</script>
<script
src=
"main.dart.js"
type=
"application/javascript"
></script>
</body>
</html>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment