mirror of
https://github.com/discourse/discourse.git
synced 2024-12-24 13:23:53 +08:00
aa9c59a24b
In our test suite, we sometimes see ChunkLoadErrors. This plugin should cause those failed requests to be retried seamlessly. It'll also help clients with flaky internet connections in production.
253 lines
7.7 KiB
JavaScript
253 lines
7.7 KiB
JavaScript
"use strict";
|
|
|
|
const EmberApp = require("ember-cli/lib/broccoli/ember-app");
|
|
const path = require("path");
|
|
const mergeTrees = require("broccoli-merge-trees");
|
|
const concat = require("broccoli-concat");
|
|
const { createI18nTree } = require("./lib/translation-plugin");
|
|
const { parsePluginClientSettings } = require("./lib/site-settings-plugin");
|
|
const discourseScss = require("./lib/discourse-scss");
|
|
const generateScriptsTree = require("./lib/scripts");
|
|
const funnel = require("broccoli-funnel");
|
|
const DeprecationSilencer = require("deprecation-silencer");
|
|
const { compatBuild } = require("@embroider/compat");
|
|
const { Webpack } = require("@embroider/webpack");
|
|
const { StatsWriterPlugin } = require("webpack-stats-plugin");
|
|
const { RetryChunkLoadPlugin } = require("webpack-retry-chunk-load-plugin");
|
|
const withSideWatch = require("./lib/with-side-watch");
|
|
const RawHandlebarsCompiler = require("discourse-hbr/raw-handlebars-compiler");
|
|
const crypto = require("crypto");
|
|
const commonBabelConfig = require("./lib/common-babel-config");
|
|
const TerserPlugin = require("terser-webpack-plugin");
|
|
|
|
process.env.BROCCOLI_ENABLED_MEMOIZE = true;
|
|
|
|
module.exports = function (defaults) {
|
|
const discourseRoot = path.resolve("../../../..");
|
|
const vendorJs = discourseRoot + "/vendor/assets/javascripts/";
|
|
|
|
// Silence deprecations which we are aware of - see `lib/deprecation-silencer.js`
|
|
DeprecationSilencer.silence(console, "warn");
|
|
DeprecationSilencer.silence(defaults.project.ui, "writeWarnLine");
|
|
|
|
const isProduction = EmberApp.env().includes("production");
|
|
|
|
const app = new EmberApp(defaults, {
|
|
autoRun: false,
|
|
"ember-qunit": {
|
|
insertContentForTestBody: false,
|
|
},
|
|
sourcemaps: {
|
|
// There seems to be a bug with broccoli-concat when sourcemaps are disabled
|
|
// that causes the `app.import` statements below to fail in production mode.
|
|
// This forces the use of `fast-sourcemap-concat` which works in production.
|
|
enabled: true,
|
|
},
|
|
fingerprint: {
|
|
// Handled by Rails asset pipeline
|
|
enabled: false,
|
|
},
|
|
SRI: {
|
|
// We don't use SRI in Rails. Disable here to match:
|
|
enabled: false,
|
|
},
|
|
|
|
"ember-cli-deprecation-workflow": {
|
|
enabled: true,
|
|
},
|
|
|
|
"ember-cli-terser": {
|
|
enabled: isProduction,
|
|
exclude: ["**/highlightjs/*", "**/javascripts/*"],
|
|
},
|
|
|
|
...commonBabelConfig(),
|
|
|
|
vendorFiles: {
|
|
// Freedom patch - includes bug fix and async stack support
|
|
// https://github.com/discourse/backburner.js/commits/discourse-patches
|
|
backburner:
|
|
"node_modules/@discourse/backburner.js/dist/named-amd/backburner.js",
|
|
},
|
|
|
|
trees: {
|
|
app: RawHandlebarsCompiler(
|
|
withSideWatch("app", {
|
|
watching: ["../discourse-markdown-it", "../truth-helpers"],
|
|
})
|
|
),
|
|
},
|
|
});
|
|
|
|
// WARNING: We should only import scripts here if they are not in NPM.
|
|
app.import(discourseRoot + "/app/assets/javascripts/polyfills.js");
|
|
|
|
app.import(
|
|
discourseRoot +
|
|
"/app/assets/javascripts/discourse/public/assets/scripts/module-shims.js"
|
|
);
|
|
|
|
const discoursePluginsTree = app.project
|
|
.findAddonByName("discourse-plugins")
|
|
.generatePluginsTree(app.tests);
|
|
|
|
const adminTree = app.project.findAddonByName("admin").treeForAddonBundle();
|
|
|
|
const testStylesheetTree = mergeTrees([
|
|
discourseScss(`${discourseRoot}/app/assets/stylesheets`, "qunit.scss"),
|
|
discourseScss(
|
|
`${discourseRoot}/app/assets/stylesheets`,
|
|
"qunit-custom.scss"
|
|
),
|
|
]);
|
|
app.project.liveReloadFilterPatterns = [/.*\.scss/];
|
|
|
|
const terserPlugin = app.project.findAddonByName("ember-cli-terser");
|
|
const applyTerser = (tree) => terserPlugin.postprocessTree("all", tree);
|
|
|
|
let extraPublicTrees = [
|
|
createI18nTree(discourseRoot, vendorJs),
|
|
parsePluginClientSettings(discourseRoot, vendorJs, app),
|
|
funnel(`${discourseRoot}/public/javascripts`, { destDir: "javascripts" }),
|
|
applyTerser(
|
|
concat(adminTree, {
|
|
inputFiles: ["**/*.js"],
|
|
outputFile: `assets/admin.js`,
|
|
})
|
|
),
|
|
applyTerser(generateScriptsTree(app)),
|
|
applyTerser(discoursePluginsTree),
|
|
testStylesheetTree,
|
|
];
|
|
|
|
const assetCachebuster = process.env["DISCOURSE_ASSET_URL_SALT"] || "";
|
|
const cachebusterHash = crypto
|
|
.createHash("md5")
|
|
.update(assetCachebuster)
|
|
.digest("hex")
|
|
.slice(0, 8);
|
|
|
|
const appTree = compatBuild(app, Webpack, {
|
|
splitAtRoutes: ["wizard"],
|
|
staticAppPaths: ["static"],
|
|
packagerOptions: {
|
|
webpackConfig: {
|
|
devtool:
|
|
process.env.CHEAP_SOURCE_MAPS === "1"
|
|
? "cheap-source-map"
|
|
: "source-map",
|
|
output: {
|
|
publicPath: "auto",
|
|
filename: `assets/chunk.[chunkhash].${cachebusterHash}.js`,
|
|
chunkFilename: `assets/chunk.[chunkhash].${cachebusterHash}.js`,
|
|
},
|
|
optimization: {
|
|
minimize: isProduction,
|
|
minimizer: [
|
|
new TerserPlugin({
|
|
minify: TerserPlugin.swcMinify,
|
|
terserOptions: {
|
|
compress: {
|
|
// Stop swc unwrapping 'unnecessary' IIFE wrappers which are added by Babel
|
|
// to workaround a bug in Safari 15 class fields.
|
|
inline: false,
|
|
reduce_funcs: false,
|
|
},
|
|
},
|
|
}),
|
|
],
|
|
},
|
|
cache: isProduction
|
|
? false
|
|
: {
|
|
type: "memory",
|
|
maxGenerations: 1,
|
|
},
|
|
entry: {
|
|
"assets/discourse.js/features/markdown-it.js": {
|
|
import: "./static/markdown-it",
|
|
dependOn: "assets/discourse.js",
|
|
runtime: false,
|
|
},
|
|
},
|
|
externals: [
|
|
function ({ request }, callback) {
|
|
if (
|
|
!request.includes("-embroider-implicit") &&
|
|
// TODO: delete special case for jquery when removing app.import() above
|
|
(request.startsWith("admin/") ||
|
|
request.startsWith("discourse/plugins/") ||
|
|
request.startsWith("discourse/theme-"))
|
|
) {
|
|
callback(null, request, "commonjs");
|
|
} else {
|
|
callback();
|
|
}
|
|
},
|
|
],
|
|
module: {
|
|
parser: {
|
|
javascript: {
|
|
exportsPresence: "error",
|
|
},
|
|
},
|
|
},
|
|
plugins: [
|
|
// The server use this output to map each asset to its chunks
|
|
new StatsWriterPlugin({
|
|
filename: "assets.json",
|
|
stats: {
|
|
all: false,
|
|
entrypoints: true,
|
|
},
|
|
transform({ entrypoints }) {
|
|
let names = Object.keys(entrypoints);
|
|
let output = {};
|
|
|
|
for (let name of names.sort()) {
|
|
let assets = entrypoints[name].assets.map(
|
|
(asset) => asset.name
|
|
);
|
|
|
|
let parent = names.find((parentName) =>
|
|
name.startsWith(parentName + "/")
|
|
);
|
|
|
|
if (parent) {
|
|
name = name.slice(parent.length + 1);
|
|
output[parent][name] = { assets };
|
|
} else {
|
|
output[name] = { assets };
|
|
}
|
|
}
|
|
|
|
return JSON.stringify(output, null, 2);
|
|
},
|
|
}),
|
|
new RetryChunkLoadPlugin({
|
|
retryDelay: 200,
|
|
maxRetries: 2,
|
|
chunks: ["assets/discourse.js"],
|
|
}),
|
|
],
|
|
},
|
|
},
|
|
skipBabel: [
|
|
{
|
|
package: "qunit",
|
|
},
|
|
{
|
|
package: "sinon",
|
|
},
|
|
{
|
|
package: "@json-editor/json-editor",
|
|
},
|
|
{
|
|
package: "ace-builds",
|
|
},
|
|
],
|
|
});
|
|
|
|
return mergeTrees([appTree, mergeTrees(extraPublicTrees)]);
|
|
};
|