mirror of
https://github.com/discourse/discourse.git
synced 2024-11-29 17:45:03 +08:00
a169dc6832
This reverts commit 7217dcb67a
.
https://meta.discourse.org/t/failed-to-bootstrap-due-to-out-of-memory-killer/188141/18?u=osama
Precompiling test_helper.js is so expensive that it can make bootstrap
fail on servers with limited resources (2GB RAM). We will find another
way that doesn't require much resources.
365 lines
11 KiB
Ruby
365 lines
11 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
def public_root
|
|
"#{Rails.root}/public"
|
|
end
|
|
|
|
def public_js
|
|
"#{public_root}/javascripts"
|
|
end
|
|
|
|
def vendor_js
|
|
"#{Rails.root}/vendor/assets/javascripts"
|
|
end
|
|
|
|
def library_src
|
|
"#{Rails.root}/node_modules"
|
|
end
|
|
|
|
def html_for_section(group)
|
|
icons = group["icons"].map do |icon|
|
|
class_attr = icon["diversity"] ? " class=\"diversity\"" : ""
|
|
" {{replace-emoji \":#{icon['name']}:\" (hash lazy=true#{class_attr})}}"
|
|
end
|
|
|
|
<<~SECTION
|
|
<div class="section" data-section="#{group["name"]}">
|
|
<div class="section-header">
|
|
<span class="title">{{i18n "emoji_picker.#{group["name"]}"}}</span>
|
|
</div>
|
|
<div class="section-group">
|
|
#{icons.join("\n").strip}
|
|
</div>
|
|
</div>
|
|
SECTION
|
|
end
|
|
|
|
def write_template(path, task_name, template)
|
|
header = <<~HEADER
|
|
// DO NOT EDIT THIS FILE!!!
|
|
// Update it by running `rake javascript:#{task_name}`
|
|
HEADER
|
|
|
|
basename = File.basename(path)
|
|
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
|
|
|
|
File.write(output_path, "#{header}\n\n#{template}")
|
|
puts "#{basename} created"
|
|
%x{yarn run prettier --write #{output_path}}
|
|
puts "#{basename} prettified"
|
|
end
|
|
|
|
def write_hbs_template(path, task_name, template)
|
|
header = <<~HEADER
|
|
{{!-- DO NOT EDIT THIS FILE!!! --}}
|
|
{{!-- Update it by running `rake javascript:#{task_name}` --}}
|
|
HEADER
|
|
|
|
basename = File.basename(path)
|
|
output_path = "#{Rails.root}/app/assets/javascripts/#{path}"
|
|
File.write(output_path, "#{header}\n#{template}")
|
|
puts "#{basename} created"
|
|
end
|
|
|
|
def dependencies
|
|
[
|
|
{
|
|
source: 'bootstrap/js/modal.js',
|
|
destination: 'bootstrap-modal.js'
|
|
}, {
|
|
source: 'ace-builds/src-min-noconflict/ace.js',
|
|
destination: 'ace.js',
|
|
public: true
|
|
}, {
|
|
source: '@json-editor/json-editor/dist/jsoneditor.js',
|
|
package_name: '@json-editor/json-editor',
|
|
public: true
|
|
}, {
|
|
source: 'chart.js/dist/Chart.min.js',
|
|
public: true
|
|
}, {
|
|
source: 'chartjs-plugin-datalabels/dist/chartjs-plugin-datalabels.min.js',
|
|
public: true
|
|
}, {
|
|
source: 'diffhtml/dist/diffhtml.min.js',
|
|
public: true
|
|
}, {
|
|
source: 'magnific-popup/dist/jquery.magnific-popup.min.js',
|
|
public: true
|
|
}, {
|
|
source: 'pikaday/pikaday.js',
|
|
public: true
|
|
}, {
|
|
source: 'spectrum-colorpicker/spectrum.js',
|
|
uglify: true,
|
|
public: true
|
|
}, {
|
|
source: 'spectrum-colorpicker/spectrum.css',
|
|
public: true
|
|
}, {
|
|
source: 'handlebars/dist/handlebars.js'
|
|
}, {
|
|
source: 'handlebars/dist/handlebars.runtime.js'
|
|
}, {
|
|
source: '@highlightjs/cdn-assets/.',
|
|
destination: 'highlightjs'
|
|
}, {
|
|
source: 'jquery.autoellipsis/src/jquery.autoellipsis.js',
|
|
destination: 'jquery.autoellipsis-1.0.10.js'
|
|
}, {
|
|
source: 'jquery-color/dist/jquery.color.js'
|
|
}, {
|
|
source: 'blueimp-file-upload/js/jquery.fileupload.js',
|
|
}, {
|
|
source: 'blueimp-file-upload/js/jquery.iframe-transport.js',
|
|
}, {
|
|
source: 'blueimp-file-upload/js/vendor/jquery.ui.widget.js',
|
|
}, {
|
|
source: 'jquery/dist/jquery.js'
|
|
}, {
|
|
source: 'jquery-tags-input/src/jquery.tagsinput.js'
|
|
}, {
|
|
source: 'markdown-it/dist/markdown-it.js'
|
|
}, {
|
|
source: 'mousetrap/mousetrap.js'
|
|
}, {
|
|
source: 'moment/moment.js'
|
|
}, {
|
|
source: 'moment/locale/.',
|
|
destination: 'moment-locale',
|
|
}, {
|
|
source: 'moment-timezone/builds/moment-timezone-with-data-10-year-range.js',
|
|
destination: 'moment-timezone-with-data.js'
|
|
}, {
|
|
source: 'lodash.js',
|
|
destination: 'lodash.js'
|
|
}, {
|
|
source: 'moment-timezone-names-translations/locales/.',
|
|
destination: 'moment-timezone-names-locale'
|
|
}, {
|
|
source: 'mousetrap/plugins/global-bind/mousetrap-global-bind.js'
|
|
}, {
|
|
source: 'resumablejs/resumable.js'
|
|
}, {
|
|
# TODO: drop when we eventually drop IE11, this will land in iOS in version 13
|
|
source: 'intersection-observer/intersection-observer.js'
|
|
}, {
|
|
source: 'workbox-sw/build/.',
|
|
destination: 'workbox',
|
|
public: true,
|
|
skip_versioning: true
|
|
}, {
|
|
source: 'workbox-routing/build/.',
|
|
destination: 'workbox',
|
|
public: true,
|
|
skip_versioning: true
|
|
}, {
|
|
source: 'workbox-core/build/.',
|
|
destination: 'workbox',
|
|
public: true,
|
|
skip_versioning: true
|
|
}, {
|
|
source: 'workbox-strategies/build/.',
|
|
destination: 'workbox',
|
|
public: true,
|
|
skip_versioning: true
|
|
}, {
|
|
source: 'workbox-expiration/build/.',
|
|
destination: 'workbox',
|
|
public: true,
|
|
skip_versioning: true
|
|
}, {
|
|
source: 'workbox-cacheable-response/build/.',
|
|
destination: 'workbox',
|
|
skip_versioning: true,
|
|
public: true
|
|
}, {
|
|
source: '@popperjs/core/dist/umd/popper.js'
|
|
}, {
|
|
source: '@popperjs/core/dist/umd/popper.js.map',
|
|
public_root: true
|
|
},
|
|
{
|
|
source: 'route-recognizer/dist/route-recognizer.js'
|
|
}, {
|
|
source: 'route-recognizer/dist/route-recognizer.js.map',
|
|
public_root: true
|
|
},
|
|
|
|
]
|
|
end
|
|
|
|
def node_package_name(f)
|
|
f[:package_name] || f[:source].split('/').first
|
|
end
|
|
|
|
def public_path_name(f)
|
|
f[:destination] || node_package_name(f)
|
|
end
|
|
|
|
task 'javascript:update_constants' => :environment do
|
|
task_name = 'update_constants'
|
|
|
|
write_template("discourse/app/lib/constants.js", task_name, <<~JS)
|
|
export const SEARCH_PRIORITIES = #{Searchable::PRIORITIES.to_json};
|
|
|
|
export const SEARCH_PHRASE_REGEXP = '#{Search::PHRASE_MATCH_REGEXP_PATTERN}';
|
|
JS
|
|
|
|
pretty_notifications = Notification.types.map do |n|
|
|
" #{n[0]}: #{n[1]},"
|
|
end.join("\n")
|
|
|
|
write_template("discourse/tests/fixtures/concerns/notification-types.js", task_name, <<~JS)
|
|
export const NOTIFICATION_TYPES = {
|
|
#{pretty_notifications}
|
|
};
|
|
JS
|
|
|
|
write_template("pretty-text/addon/emoji/data.js", task_name, <<~JS)
|
|
export const emojis = #{Emoji.standard.map(&:name).flatten.inspect};
|
|
export const tonableEmojis = #{Emoji.tonable_emojis.flatten.inspect};
|
|
export const aliases = #{Emoji.aliases.inspect.gsub("=>", ":")};
|
|
export const searchAliases = #{Emoji.search_aliases.inspect.gsub("=>", ":")};
|
|
export const translations = #{Emoji.translations.inspect.gsub("=>", ":")};
|
|
export const replacements = #{Emoji.unicode_replacements_json};
|
|
JS
|
|
|
|
write_template("pretty-text/addon/emoji/version.js", task_name, <<~JS)
|
|
export const IMAGE_VERSION = "#{Emoji::EMOJI_VERSION}";
|
|
JS
|
|
|
|
groups_json = JSON.parse(File.read("lib/emoji/groups.json"))
|
|
|
|
emoji_buttons = groups_json.map do |group|
|
|
<<~BUTTON
|
|
<button type="button" data-section="#{group["name"]}" {{action onCategorySelection "#{group["name"]}"}} class="btn btn-default category-button emoji">
|
|
{{replace-emoji ":#{group["tabicon"]}:"}}
|
|
</button>
|
|
BUTTON
|
|
end
|
|
|
|
emoji_sections = groups_json.map { |group| html_for_section(group) }
|
|
|
|
components_dir = "discourse/app/templates/components"
|
|
write_hbs_template("#{components_dir}/emoji-group-buttons.hbs", task_name, emoji_buttons.join)
|
|
write_hbs_template("#{components_dir}/emoji-group-sections.hbs", task_name, emoji_sections.join)
|
|
|
|
end
|
|
|
|
task 'javascript:update' => 'clean_up' do
|
|
require 'uglifier'
|
|
|
|
yarn = system("yarn install")
|
|
abort('Unable to run "yarn install"') unless yarn
|
|
|
|
versions = {}
|
|
start = Time.now
|
|
|
|
dependencies.each do |f|
|
|
src = "#{library_src}/#{f[:source]}"
|
|
|
|
unless f[:destination]
|
|
filename = f[:source].split("/").last
|
|
else
|
|
filename = f[:destination]
|
|
end
|
|
|
|
if src.include? "highlightjs"
|
|
puts "Cleanup highlightjs styles and install smaller test bundle"
|
|
system("rm -rf node_modules/@highlightjs/cdn-assets/styles")
|
|
|
|
# We don't need every language for tests
|
|
langs = ['javascript', 'sql', 'ruby']
|
|
test_bundle_dest = 'vendor/assets/javascripts/highlightjs/highlight-test-bundle.min.js'
|
|
File.write(test_bundle_dest, HighlightJs.bundle(langs))
|
|
end
|
|
|
|
if f[:public_root]
|
|
dest = "#{public_root}/#{filename}"
|
|
elsif f[:public]
|
|
if f[:skip_versioning]
|
|
dest = "#{public_js}/#{filename}"
|
|
else
|
|
package_dir_name = public_path_name(f)
|
|
package_version = JSON.parse(File.read("#{library_src}/#{node_package_name(f)}/package.json"))["version"]
|
|
versions[filename] = "#{package_dir_name}/#{package_version}/#{filename}"
|
|
|
|
path = "#{public_js}/#{package_dir_name}/#{package_version}"
|
|
dest = "#{path}/#{filename}"
|
|
|
|
FileUtils.mkdir_p(path) unless File.exists?(path)
|
|
end
|
|
else
|
|
dest = "#{vendor_js}/#{filename}"
|
|
end
|
|
|
|
if src.include? "ace.js"
|
|
versions["ace/ace.js"] = versions.delete("ace.js")
|
|
ace_root = "#{library_src}/ace-builds/src-min-noconflict/"
|
|
addtl_files = [ "ext-searchbox", "mode-html", "mode-scss", "mode-sql", "theme-chrome", "worker-html"]
|
|
dest_path = dest.split('/')[0..-2].join('/')
|
|
addtl_files.each do |file|
|
|
FileUtils.cp_r("#{ace_root}#{file}.js", dest_path)
|
|
end
|
|
end
|
|
|
|
# lodash.js needs building
|
|
if src.include? "lodash.js"
|
|
puts "Building custom lodash.js build"
|
|
system('yarn run lodash include="each,filter,map,range,first,isEmpty,chain,extend,every,omit,merge,union,sortBy,uniq,intersection,reject,compact,reduce,debounce,throttle,values,pick,keys,flatten,min,max,isArray,delay,isString,isEqual,without,invoke,clone,findIndex,find,groupBy" minus="template" -d -o "node_modules/lodash.js"')
|
|
end
|
|
|
|
unless File.exists?(dest)
|
|
STDERR.puts "New dependency added: #{dest}"
|
|
end
|
|
|
|
if f[:uglify]
|
|
File.write(dest, Uglifier.new.compile(File.read(src)))
|
|
else
|
|
FileUtils.cp_r(src, dest)
|
|
end
|
|
|
|
# use absolute path for popper.js's sourcemap
|
|
# avoids noisy console warnings in dev environment for non-homepage paths
|
|
if dest.end_with? "popper.js"
|
|
File.open(dest) do |file|
|
|
contents = file.read
|
|
contents.gsub!("sourceMappingURL=popper", "sourceMappingURL=/popper")
|
|
File.open(dest, "w+") { |d| d.write(contents) }
|
|
end
|
|
end
|
|
end
|
|
|
|
write_template("discourse/app/lib/public-js-versions.js", "update", <<~JS)
|
|
export const PUBLIC_JS_VERSIONS = #{versions.to_json};
|
|
JS
|
|
|
|
STDERR.puts "Completed copying dependencies: #{(Time.now - start).round(2)} secs"
|
|
end
|
|
|
|
task 'javascript:clean_up' do
|
|
processed = []
|
|
dependencies.each do |f|
|
|
next unless f[:public] && !f[:skip_versioning]
|
|
|
|
package_dir_name = public_path_name(f)
|
|
next if processed.include?(package_dir_name)
|
|
|
|
versions = Dir["#{File.join(public_js, package_dir_name)}/*"].collect { |p| p.split('/').last }
|
|
next unless versions.present?
|
|
|
|
versions = versions.sort { |a, b| Gem::Version.new(a) <=> Gem::Version.new(b) }
|
|
puts "Keeping #{package_dir_name} version: #{versions[-1]}"
|
|
|
|
# Keep the most recent version
|
|
versions[0..-2].each do |version|
|
|
remove_path = File.join(public_js, package_dir_name, version)
|
|
puts "Removing: #{remove_path}"
|
|
FileUtils.remove_dir(remove_path)
|
|
end
|
|
|
|
processed << package_dir_name
|
|
end
|
|
end
|