Theme javascript is now minified using Terser, just like our core/plugin JS bundles. This reduces the amount of data sent over the network. This commit also introduces sourcemaps for theme JS. Browser developer tools will now be able show each source file separately when browsing, and also in backtraces. For theme test JS, the sourcemap is inlined for simplicity. Network load is not a concern for tests.
156 lines
6.6 KiB
Ruby
156 lines
6.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe ThemeJavascriptCompiler do
|
|
let(:compiler) { ThemeJavascriptCompiler.new(1, 'marks') }
|
|
|
|
describe "#append_raw_template" do
|
|
it 'uses the correct template paths' do
|
|
template = "<h1>hello</h1>"
|
|
name = "/path/to/templates1"
|
|
compiler.append_raw_template("#{name}.raw", template)
|
|
expect(compiler.raw_content.to_s).to include("addRawTemplate(\"#{name}\"")
|
|
|
|
name = "/path/to/templates2"
|
|
compiler.append_raw_template("#{name}.hbr", template)
|
|
expect(compiler.raw_content.to_s).to include("addRawTemplate(\"#{name}\"")
|
|
|
|
name = "/path/to/templates3"
|
|
compiler.append_raw_template("#{name}.hbs", template)
|
|
expect(compiler.raw_content.to_s).to include("addRawTemplate(\"#{name}.hbs\"")
|
|
end
|
|
end
|
|
|
|
describe "#append_ember_template" do
|
|
it 'maintains module names so that discourse-boot.js can correct them' do
|
|
compiler.append_ember_template("/connectors/blah-1", "{{var}}")
|
|
expect(compiler.raw_content.to_s).to include("define(\"discourse/theme-1/connectors/blah-1\", [\"exports\", \"@ember/template-factory\"]")
|
|
|
|
compiler.append_ember_template("connectors/blah-2", "{{var}}")
|
|
expect(compiler.raw_content.to_s).to include("define(\"discourse/theme-1/connectors/blah-2\", [\"exports\", \"@ember/template-factory\"]")
|
|
|
|
compiler.append_ember_template("javascripts/connectors/blah-3", "{{var}}")
|
|
expect(compiler.raw_content.to_s).to include("define(\"discourse/theme-1/javascripts/connectors/blah-3\", [\"exports\", \"@ember/template-factory\"]")
|
|
end
|
|
end
|
|
|
|
describe "connector module name handling" do
|
|
it 'separates colocated connectors to avoid module name clash' do
|
|
# Colocated under `/connectors`
|
|
compiler = ThemeJavascriptCompiler.new(1, 'marks')
|
|
compiler.append_ember_template("connectors/outlet/blah-1", "{{var}}")
|
|
compiler.append_module("console.log('test')", "connectors/outlet/blah-1")
|
|
expect(compiler.raw_content.to_s).to include("discourse/theme-1/connectors/outlet/blah-1")
|
|
expect(compiler.raw_content.to_s).to include("discourse/theme-1/templates/connectors/outlet/blah-1")
|
|
|
|
# Colocated under `/templates/connectors`
|
|
compiler = ThemeJavascriptCompiler.new(1, 'marks')
|
|
compiler.append_ember_template("templates/connectors/outlet/blah-1", "{{var}}")
|
|
compiler.append_module("console.log('test')", "templates/connectors/outlet/blah-1")
|
|
expect(compiler.raw_content.to_s).to include("discourse/theme-1/connectors/outlet/blah-1")
|
|
expect(compiler.raw_content.to_s).to include("discourse/theme-1/templates/connectors/outlet/blah-1")
|
|
|
|
# Not colocated
|
|
compiler = ThemeJavascriptCompiler.new(1, 'marks')
|
|
compiler.append_ember_template("templates/connectors/outlet/blah-1", "{{var}}")
|
|
compiler.append_module("console.log('test')", "connectors/outlet/blah-1")
|
|
expect(compiler.raw_content.to_s).to include("discourse/theme-1/connectors/outlet/blah-1")
|
|
expect(compiler.raw_content.to_s).to include("discourse/theme-1/templates/connectors/outlet/blah-1")
|
|
end
|
|
end
|
|
|
|
describe "error handling" do
|
|
it "handles syntax errors in raw templates" do
|
|
expect do
|
|
compiler.append_raw_template("sometemplate.hbr", "{{invalidtemplate")
|
|
end.to raise_error(ThemeJavascriptCompiler::CompileError, /Parse error on line 1/)
|
|
end
|
|
|
|
it "handles syntax errors in ember templates" do
|
|
expect do
|
|
compiler.append_ember_template("sometemplate", "{{invalidtemplate")
|
|
end.to raise_error(ThemeJavascriptCompiler::CompileError, /Parse error on line 1/)
|
|
end
|
|
end
|
|
|
|
describe "#append_tree" do
|
|
it "can handle multiple modules" do
|
|
compiler.append_tree(
|
|
{
|
|
"discourse/components/mycomponent.js" => <<~JS,
|
|
import Component from "@glimmer/component";
|
|
export default class MyComponent extends Component {}
|
|
JS
|
|
"discourse/templates/components/mycomponent.hbs" => "{{my-component-template}}"
|
|
}
|
|
)
|
|
expect(compiler.raw_content).to include('define("discourse/theme-1/components/mycomponent"')
|
|
expect(compiler.raw_content).to include('define("discourse/theme-1/discourse/templates/components/mycomponent"')
|
|
end
|
|
|
|
it "handles colocated components" do
|
|
compiler.append_tree(
|
|
{
|
|
"discourse/components/mycomponent.js" => <<~JS,
|
|
import Component from "@glimmer/component";
|
|
export default class MyComponent extends Component {}
|
|
JS
|
|
"discourse/components/mycomponent.hbs" => "{{my-component-template}}"
|
|
}
|
|
)
|
|
expect(compiler.raw_content).to include("__COLOCATED_TEMPLATE__ =")
|
|
expect(compiler.raw_content).to include("setComponentTemplate")
|
|
end
|
|
|
|
it "prints error when default export missing" do
|
|
compiler.append_tree(
|
|
{
|
|
"discourse/components/mycomponent.js" => <<~JS,
|
|
import Component from "@glimmer/component";
|
|
class MyComponent extends Component {}
|
|
JS
|
|
"discourse/components/mycomponent.hbs" => "{{my-component-template}}"
|
|
}
|
|
)
|
|
expect(compiler.raw_content).to include("__COLOCATED_TEMPLATE__ =")
|
|
expect(compiler.raw_content).to include("throw new Error")
|
|
end
|
|
|
|
it "handles template-only components" do
|
|
compiler.append_tree(
|
|
{
|
|
"discourse/components/mycomponent.hbs" => "{{my-component-template}}"
|
|
}
|
|
)
|
|
expect(compiler.raw_content).to include("__COLOCATED_TEMPLATE__ =")
|
|
expect(compiler.raw_content).to include("setComponentTemplate")
|
|
expect(compiler.raw_content).to include("@ember/component/template-only")
|
|
end
|
|
end
|
|
|
|
describe "terser compilation" do
|
|
it "applies terser and provides sourcemaps" do
|
|
sources = {
|
|
"multiply.js" => "let multiply = (firstValue, secondValue) => firstValue * secondValue;",
|
|
"add.js" => "let add = (firstValue, secondValue) => firstValue + secondValue;"
|
|
}
|
|
|
|
compiler.append_tree(sources)
|
|
|
|
expect(compiler.content).to include("multiply")
|
|
expect(compiler.content).to include("add")
|
|
|
|
map = JSON.parse(compiler.source_map)
|
|
expect(map["sources"]).to contain_exactly(*sources.keys)
|
|
expect(map["sourcesContent"].to_s).to include("let multiply")
|
|
expect(map["sourcesContent"].to_s).to include("let add")
|
|
expect(map["sourceRoot"]).to eq("theme-1/")
|
|
end
|
|
|
|
it "handles invalid JS" do
|
|
compiler.append_raw_script("filename.js", "if(someCondition")
|
|
expect(compiler.content).to include('console.error("[THEME 1')
|
|
expect(compiler.content).to include('Unexpected token')
|
|
end
|
|
end
|
|
end
|