mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 07:23:30 +08:00
1. Remove 'federated exports' system, which was named entrypoint exports
for every module inside the plugin. Replace it with a single import of
the target plugin's 'compatModules', and then update call sites to do a
'just in time' lookup of the module and export. This is implemented in a
new `babel-resolve-plugin-imports` plugin
2. Update theme & plugin build systems to produce a list of external
plugins which are imported. For plugins, it's stored in the manifest.
For themes, it's stored in a new column of the javascript_caches table.
3. Refactor theme extra_js loading to use a more structured data model,
and move the HTML generation to the erb template
4. Update core importmap to identify any missing plugin dependencies and
add a fake placeholder module for them. This allows optional imports to
exist without causing a boot error. The imported values will resolve to
'null'.
5. Update core plugins to remove use of `optionalRequire`, and replace
it with regular imports, and a `with { discourseImport: "optional" }`
suffix. This is functionally equivalent to optionalRequire, but without
leaning on the legacy `loader.js` system of core
6. Add support for `with { discourseImport: "optional" }` for
plugins/themes importing core modules. This is useful when a
theme/plugin needs to target multiple versions of Discourse core.
Co-authored-by: Jarek Radosz <jarek@cvx.dev>
35 lines
1.4 KiB
Ruby
Vendored
35 lines
1.4 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe "Theme cross-bundle plugin imports" do
|
|
fab!(:theme)
|
|
|
|
before { Fabricate(:admin) } # so "/" renders the app instead of the install wizard
|
|
|
|
def import_map
|
|
map = response.body[%r{<script type="importmap"[^>]*>(.*?)</script>}m, 1]
|
|
JSON.parse(map)["imports"]
|
|
end
|
|
|
|
it "stubs imports of an absent plugin: null for optional, throwing for required" do
|
|
theme.set_field(target: :extra_js, name: "discourse/initializers/cross-bundle.js", value: <<~JS)
|
|
import Optional from "discourse/plugins/absent-optional-plugin/lib/thing" with { discourseImport: "optional" };
|
|
import Required from "discourse/plugins/absent-required-plugin/lib/thing" with { discourseImport: "required" };
|
|
export default { name: "cross-bundle", initialize() { Optional(); Required(); } };
|
|
JS
|
|
theme.save!
|
|
SiteSetting.default_theme_id = theme.id
|
|
|
|
get "/"
|
|
expect(response.status).to eq(200)
|
|
|
|
# Optional import of a missing plugin resolves to a null-returning stub.
|
|
expect(import_map["discourse/plugins/absent-optional-plugin?"]).to eq(
|
|
Plugin::JsManager.optional_plugin_stub,
|
|
)
|
|
|
|
# Required import of a missing plugin resolves to a stub that throws on import.
|
|
expect(import_map["discourse/plugins/absent-required-plugin"]).to eq(
|
|
Plugin::JsManager.required_plugin_stub("absent-required-plugin"),
|
|
)
|
|
end
|
|
end
|