Commit 348e043d authored by dpapad's avatar dpapad Committed by Commit Bot

WebUI: Add GN rule for inlining Polymer HTML into JS files.

Add a new js_html_template() rule to inline HTML content within JS
files during build time.

Having HTML in JS is a requirement of Polymer3. This GN rule allows
HTML development to still happen within HTML files which eliminates
any inconvenience of that constraint during development.

Moreover, js_html_template() is capable of extracting HTML content from
existing Polymer2 HTML files, such that HTML is not duplicated across
v2 and v3 element implementations during a potential migration.

Bug: 965770
Change-Id: I05fdc1a30968f9793eb6ecb59601afc1c11bfb33
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1648811
Commit-Queue: Demetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: default avatarRebekah Potter <rbpotter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#667359}
parent c5072ad9
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Presubmit script for files in tools/polymer/
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into depot_tools.
"""
def RunPolymerTests(input_api, output_api):
presubmit_path = input_api.PresubmitLocalPath()
sources = ['polymer_test.py']
tests = [input_api.os_path.join(presubmit_path, s) for s in sources]
return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
def _CheckChangeOnUploadOrCommit(input_api, output_api):
results = []
affected = input_api.AffectedFiles()
webui_sources = set(['polymer.py'])
affected_files = [input_api.os_path.basename(f.LocalPath()) for f in affected]
if webui_sources.intersection(set(affected_files)):
results += RunPolymerTests(input_api, output_api)
return results
def CheckChangeOnUpload(input_api, output_api):
return _CheckChangeOnUploadOrCommit(input_api, output_api)
def CheckChangeOnCommit(input_api, output_api):
return _CheckChangeOnUploadOrCommit(input_api, output_api)
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
template("js_html_template") {
action(target_name + "_js_html_template") {
script = "//tools/polymer/polymer.py"
inputs = [
invoker.js_file,
invoker.html_file,
]
outputs = [
"$target_gen_dir/" + invoker.js_file,
]
args = [
"--js_file",
invoker.js_file,
"--html_file",
invoker.html_file,
"--html_type",
invoker.html_type,
"--in_folder",
rebase_path(".", root_build_dir),
"--out_folder",
rebase_path(target_gen_dir, root_build_dir),
]
}
}
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Helper script for inlining HTML content from an HTML to a JS file. This is
# necessary for Polymer3 UI elements. The following |html_type| options are
# provided
# - dom-module: Extracts HTML content from a Polymer2 HTML file hosting a
# dom-module.
# - custom-style: Extracts HTML content from a Polymer HTML file hosting a
# custom-style.
# - v3-ready: Extracts HTML content from a file that is only used in Polymer3.
#
# "dom-module" and "custom-style" are useful for avoiding duplicating HTML code
# between Polymer2 and Polymer3 while migration is in progress.
#
# Note: Having multiple <dom-module>s within a single HTML file is not currently
# supported by this script.
import argparse
import os
import re
import sys
_CWD = os.getcwd()
HTML_TEMPLATE_REGEX = '{__html_template__}'
def ExtractTemplate(html_file, html_type):
if html_type == 'v3-ready':
with open(html_file, 'r') as f:
return f.read()
if html_type == 'dom-module':
with open(html_file, 'r') as f:
lines = f.readlines()
start_line = -1
end_line = -1
for i, line in enumerate(lines):
if re.match(r'\s*<dom-module ', line):
assert start_line == -1
assert end_line == -1
assert re.match(r'\s*<template', lines[i + 1])
start_line = i + 2;
if re.match(r'\s*</dom-module>', line):
assert start_line != -1
assert end_line == -1
assert re.match(r'\s*</template>', lines[i - 2])
assert re.match(r'\s*<script ', lines[i - 1])
end_line = i - 3;
return ''.join(lines[start_line:end_line + 1])
assert html_type == 'custom-style'
with open(html_file, 'r') as f:
lines = f.readlines()
start_line = -1
end_line = -1
for i, line in enumerate(lines):
if re.match(r'\s*<custom-style>', line):
assert start_line == -1
assert end_line == -1
start_line = i;
if re.match(r'\s*</custom-style>', line):
assert start_line != -1
assert end_line == -1
end_line = i;
return ''.join(lines[start_line:end_line + 1])
def ProcessFile(js_file, html_file, html_type, out_folder):
html_template = ExtractTemplate(html_file, html_type)
with open(js_file) as f:
lines = f.readlines()
for i, line in enumerate(lines):
line = line.replace(HTML_TEMPLATE_REGEX, html_template)
lines[i] = line
# Reconstruct file.
out_filename = os.path.basename(js_file)
with open(os.path.join(out_folder, out_filename), 'w') as f:
for l in lines:
f.write(l)
return
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument('--in_folder', required=True)
parser.add_argument('--out_folder', required=True)
parser.add_argument('--js_file', required=True)
parser.add_argument('--html_file', required=True)
parser.add_argument(
'--html_type', choices=['dom-module', 'custom-style', 'v3-ready'],
required=True)
args = parser.parse_args(argv)
in_folder = os.path.normpath(os.path.join(_CWD, args.in_folder))
out_folder = os.path.normpath(os.path.join(_CWD, args.out_folder))
ProcessFile(
os.path.join(in_folder, args.js_file),
os.path.join(in_folder, args.html_file),
args.html_type, out_folder)
if __name__ == '__main__':
main(sys.argv[1:])
#!/usr/bin/env python
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import polymer
import os
import shutil
import tempfile
import unittest
_HERE_DIR = os.path.dirname(__file__)
class HtmlToJsTest(unittest.TestCase):
def setUp(self):
self._out_folder = None
self._tmp_dirs = []
self._tmp_src_dir = None
def tearDown(self):
for tmp_dir in self._tmp_dirs:
shutil.rmtree(tmp_dir)
def _write_file_to_src_dir(self, file_path, file_contents):
if not self._tmp_src_dir:
self._tmp_src_dir = self._create_tmp_dir()
file_path_normalized = os.path.normpath(os.path.join(self._tmp_src_dir,
file_path))
file_dir = os.path.dirname(file_path_normalized)
if not os.path.exists(file_dir):
os.makedirs(file_dir)
with open(file_path_normalized, 'w') as tmp_file:
tmp_file.write(file_contents)
def _create_tmp_dir(self):
tmp_dir = tempfile.mkdtemp(dir=_HERE_DIR)
self._tmp_dirs.append(tmp_dir)
return tmp_dir
def _read_out_file(self, file_name):
assert self._out_folder
return open(os.path.join(self._out_folder, file_name), 'r').read()
def _run_html_to_js(self, js_file, html_file, html_type):
assert not self._out_folder
self._out_folder = self._create_tmp_dir()
polymer.main([
'--in_folder', self._tmp_src_dir,
'--out_folder', self._out_folder,
'--js_file', js_file,
'--html_file', html_file,
'--html_type', html_type,
])
def _run_test_(self, html_type, src_html, src_js, expected_js):
self._write_file_to_src_dir('foo.html', src_html)
self._write_file_to_src_dir('foo.js', src_js)
self._run_html_to_js('foo.js', 'foo.html', html_type)
actual_js = self._read_out_file('foo.js')
self.assertEquals(expected_js, actual_js)
# Test case where HTML is extracted from a Polymer2 <dom-module>.
def testSuccess_DomModule(self):
self._run_test_('dom-module', '''
<link rel="import" href="../../foo/bar.html">
<link rel="import" href="chrome://resources/foo/bar.html">
<dom-module id="cr-checkbox">
<template>
<style>
div {
font-size: 2rem;
}
</style>
<div>Hello world</div>
</template>
<script src="foo.js"></script>
</dom-module>
''', '''
Polymer({
is: 'cr-foo',
_template: html`
{__html_template__}
`,
});
''', '''
Polymer({
is: 'cr-foo',
_template: html`
<style>
div {
font-size: 2rem;
}
</style>
<div>Hello world</div>
`,
});
''')
# Test case where HTML is extracted from a Polymer2 <custom-style>.
def testSuccess_CustomStyle(self):
self._run_test_('custom-style', '''
<link rel="import" href="../../foo/bar.html">
<link rel="import" href="chrome://resources/foo/bar.html">
<custom-style>
<style>
html {
--foo-bar: 2rem;
}
</style>
</custom-style>
''', '''
$_documentContainer.innerHTML = `
{__html_template__}
`;
''', '''
$_documentContainer.innerHTML = `
<custom-style>
<style>
html {
--foo-bar: 2rem;
}
</style>
</custom-style>
`;
''')
# Test case where the provided HTML is already in the form needed by Polymer3.
def testSuccess_V3Ready(self):
self._run_test_('v3-ready', '''<style>
div {
font-size: 2rem;
}
</style>
<div>Hello world</div>
''', '''
Polymer({
is: 'cr-foo',
_template: html`
{__html_template__}
`,
});
''', '''
Polymer({
is: 'cr-foo',
_template: html`
<style>
div {
font-size: 2rem;
}
</style>
<div>Hello world</div>
`,
});
''')
if __name__ == '__main__':
unittest.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