Unverified Commit b42e3469 authored by Mouad Debbar's avatar Mouad Debbar Committed by GitHub

[web] Update index.html template to support new path strategy (#67081)

parent 74fe6bff
......@@ -7,6 +7,8 @@ import 'dart:typed_data';
import 'package:dwds/data/build_result.dart';
import 'package:dwds/dwds.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart';
import 'package:logging/logging.dart' as logging;
import 'package:meta/meta.dart';
import 'package:mime/mime.dart' as mime;
......@@ -56,6 +58,9 @@ typedef DwdsLauncher = Future<Dwds> Function({
// A minimal index for projects that do not yet support web.
const String _kDefaultIndex = '''
<html>
<head>
<base href="/">
</head>
<body>
<script src="main.dart.js"></script>
</body>
......@@ -108,7 +113,9 @@ class WebAssetServer implements AssetReader {
this._modules,
this._digests,
this._buildInfo,
);
) : basePath = _parseBasePathFromIndexHtml(globals.fs.currentDirectory
.childDirectory('web')
.childFile('index.html'));
// Fallback to "application/octet-stream" on null which
// makes no claims as to the structure of the data.
......@@ -1009,17 +1016,67 @@ Future<Directory> _loadDwdsDirectory(FileSystem fileSystem, Logger logger) async
}
String _stripBasePath(String path, String basePath) {
while (path.startsWith('/')) {
path = path.substring(1);
}
path = _stripLeadingSlashes(path);
if (path.startsWith(basePath)) {
path = path.substring(basePath.length);
} else {
// The given path isn't under base path, return null to indicate that.
return null;
}
return _stripLeadingSlashes(path);
}
String _stripLeadingSlashes(String path) {
while (path.startsWith('/')) {
path = path.substring(1);
}
return path;
}
String _stripTrailingSlashes(String path) {
while (path.endsWith('/')) {
path = path.substring(0, path.length - 1);
}
return path;
}
String _parseBasePathFromIndexHtml(File indexHtml) {
final String htmlContent = indexHtml.existsSync()
? indexHtml.readAsStringSync()
: _kDefaultIndex;
final Document document = parse(htmlContent);
final Element baseElement = document.querySelector('base');
String baseHref = baseElement?.attributes == null ? null : baseElement.attributes['href'];
if (baseHref == null) {
baseHref = '';
} else if (!baseHref.startsWith('/')) {
throw ToolExit(
'Error: The base href in "web/index.html" must be absolute (i.e. start '
'with a "/"), but found: `${baseElement.outerHtml}`.\n'
'$basePathExample',
);
} else if (!baseHref.endsWith('/')) {
throw ToolExit(
'Error: The base href in "web/index.html" must end with a "/", but found: `${baseElement.outerHtml}`.\n'
'$basePathExample',
);
} else {
baseHref = _stripLeadingSlashes(_stripTrailingSlashes(baseHref));
}
return baseHref;
}
const String basePathExample = '''
For example, to serve from the root use:
<base href="/">
To serve from a subpath "foo" (i.e. http://localhost:8080/foo/ instead of http://localhost:8080/) use:
<base href="/foo/">
For more information, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
''';
......@@ -18,6 +18,7 @@ dependencies:
crypto: 2.1.5
file: 6.0.0-nullsafety.2
flutter_template_images: 1.0.1
html: 0.14.0+3
http: 0.12.2
intl: 0.16.1
meta: 1.3.0-nullsafety.3
......@@ -74,7 +75,6 @@ dependencies:
devtools_shared: 0.8.0+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
fixnum: 0.10.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
html: 0.14.0+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_parser: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
io: 0.3.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
js: 0.6.3-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
Fore more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
-->
<base href="/">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="{{description}}">
......
......@@ -55,7 +55,6 @@ void main() {
null,
null,
null,
);
});
});
......@@ -215,6 +214,85 @@ void main() {
expect(response.statusCode, HttpStatus.notFound);
}));
test('parses base path from index.html', () => testbed.run(() async {
const String htmlContent = '<html><head><base href="/foo/bar/"></head><body id="test"></body></html>';
final Directory webDir = globals.fs.currentDirectory
.childDirectory('web')
..createSync();
webDir.childFile('index.html').writeAsStringSync(htmlContent);
final WebAssetServer webAssetServer = WebAssetServer(
mockHttpServer,
packages,
InternetAddress.loopbackIPv4,
null,
null,
null,
);
expect(webAssetServer.basePath, 'foo/bar');
}));
test('handles lack of base path in index.html', () => testbed.run(() async {
const String htmlContent = '<html><head></head><body id="test"></body></html>';
final Directory webDir = globals.fs.currentDirectory
.childDirectory('web')
..createSync();
webDir.childFile('index.html').writeAsStringSync(htmlContent);
final WebAssetServer webAssetServer = WebAssetServer(
mockHttpServer,
packages,
InternetAddress.loopbackIPv4,
null,
null,
null,
);
// Defaults to "/" when there's no base element.
expect(webAssetServer.basePath, '');
}));
test('throws if base path is relative', () => testbed.run(() async {
const String htmlContent = '<html><head><base href="foo/bar/"></head><body id="test"></body></html>';
final Directory webDir = globals.fs.currentDirectory
.childDirectory('web')
..createSync();
webDir.childFile('index.html').writeAsStringSync(htmlContent);
expect(
() => WebAssetServer(
mockHttpServer,
packages,
InternetAddress.loopbackIPv4,
null,
null,
null,
),
throwsToolExit(),
);
}));
test('throws if base path does not end with slash', () => testbed.run(() async {
const String htmlContent = '<html><head><base href="/foo/bar"></head><body id="test"></body></html>';
final Directory webDir = globals.fs.currentDirectory
.childDirectory('web')
..createSync();
webDir.childFile('index.html').writeAsStringSync(htmlContent);
expect(
() => WebAssetServer(
mockHttpServer,
packages,
InternetAddress.loopbackIPv4,
null,
null,
null,
),
throwsToolExit(),
);
}));
test('serves JavaScript files from in memory cache not from manifest', () => testbed.run(() async {
webAssetServer.writeFile('foo.js', 'main() {}');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment