1
0
Fork 0
mirror of https://github.com/TryGhost/Ghost-Admin.git synced 2023-12-14 02:33:04 +01:00

Lazy-load SimpleMDE dependency in MD card (reduces main bundle by 260KB)

no issue
- use broccoli-funnel to avoid polluting the `dist/` dir with unused build artefacts
- load codemirror and simplemde CSS up-front to avoid duplicate styles and specificity problems
- pull simplemde dependency out into a separate JS file and lazy-load in `{{gh-simplemde}}` component to reduce main bundle size. Before/after:
  - `vendor.min.js 3.58 MB (795.88 KB gzipped)`
  - `vendor.min.js 3.32 MB (710.66 KB gzipped)`
This commit is contained in:
Kevin Ansfield 2019-01-21 16:06:25 +00:00
parent c0d9400cf7
commit fdebfae0ca
4 changed files with 72 additions and 23 deletions

View file

@ -65,7 +65,6 @@ const CmEditorComponent = Component.extend({
let loader = this.get('lazyLoader');
yield RSVP.all([
loader.loadStyle('codemirror', 'assets/codemirror/codemirror.css'),
loader.loadScript('codemirror', 'assets/codemirror/codemirror.js')
]);

View file

@ -4,8 +4,11 @@ import config from 'ghost-admin/config/environment';
import {assign} from '@ember/polyfills';
import {computed} from '@ember/object';
import {isEmpty} from '@ember/utils';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
export default TextArea.extend({
lazyLoader: service(),
// Public attributes
autofocus: false,
@ -60,6 +63,18 @@ export default TextArea.extend({
// instantiate the editor with the contents of value
didInsertElement() {
this._super(...arguments);
this.initSimpleMDE.perform();
},
willDestroyElement() {
this.onEditorDestroy();
this._editor.toTextArea();
delete this._editor;
this._super(...arguments);
},
initSimpleMDE: task(function* () {
yield this.lazyLoader.loadScript('simplemde', 'assets/simplemde/simplemde.js');
let editorOptions = assign(
{element: document.getElementById(this.elementId)},
@ -97,12 +112,5 @@ export default TextArea.extend({
}
this.onEditorInit(this._editor);
},
willDestroyElement() {
this.onEditorDestroy();
this._editor.toTextArea();
delete this._editor;
this._super(...arguments);
}
})
});

View file

@ -378,6 +378,11 @@
/* SimpleMDE editor
/* ---------------------------------------------------------- */
/* ensure there's no flash of unstyled textarea while initializing */
.gh-markdown-editor textarea {
visibility: hidden;
}
.gh-editor-title {
padding: 0;
}

View file

@ -6,20 +6,19 @@ const concat = require('broccoli-concat');
const mergeTrees = require('broccoli-merge-trees');
const uglify = require('broccoli-uglify-sourcemap');
const CleanCSS = require('broccoli-clean-css');
const Funnel = require('broccoli-funnel');
const environment = EmberApp.env();
const isProduction = environment === 'production';
let assetLocation, codemirrorAssets;
assetLocation = function (fileName) {
const assetLocation = function (fileName) {
if (isProduction) {
fileName = fileName.replace('.', '.min.');
}
return `/assets/${fileName}`;
};
codemirrorAssets = function () {
const codemirrorAssets = function () {
let codemirrorFiles = [
// 'lib/codemirror.css',
'theme/xq-light.css',
'lib/codemirror.js',
'mode/htmlmixed/htmlmixed.js',
@ -45,17 +44,12 @@ codemirrorAssets = function () {
sourceMapConfig: {enabled: false}
});
let cssTree = concat(tree, {
outputFile: 'assets/codemirror/codemirror.css',
inputFiles: ['**/*.css']
});
if (isProduction) {
jsTree = uglify(jsTree);
cssTree = new CleanCSS(cssTree);
}
return mergeTrees([tree, jsTree, cssTree]);
let mergedTree = mergeTrees([tree, jsTree]);
return new Funnel(mergedTree, {include: ['assets/**/*', 'theme/**/*']});
}
};
@ -67,6 +61,44 @@ codemirrorAssets = function () {
return config;
};
const simplemdeAssets = function () {
let simplemdeFiles = [
'debug/simplemde.js'
];
if (environment === 'test') {
return {import: simplemdeFiles};
}
let config = {};
config.public = {
include: simplemdeFiles,
destDir: '/',
processTree(tree) {
let jsTree = concat(tree, {
outputFile: 'assets/simplemde/simplemde.js',
inputFiles: ['debug/simplemde.js'],
sourceMapConfig: {enabled: false}
});
if (isProduction) {
jsTree = uglify(jsTree);
}
let mergedTree = mergeTrees([tree, jsTree]);
return new Funnel(mergedTree, {include: ['assets/**/*']});
}
};
// put the files in vendor ready for importing into the test-support file
if (environment === 'development') {
config.vendor = simplemdeFiles;
}
return config;
};
module.exports = function (defaults) {
let app = new EmberApp(defaults, {
'ember-cli-babel': {
@ -103,7 +135,8 @@ module.exports = function (defaults) {
}
},
nodeAssets: {
codemirror: codemirrorAssets()
codemirror: codemirrorAssets(),
simplemde: simplemdeAssets()
},
svgJar: {
strategy: 'inline',
@ -130,14 +163,17 @@ module.exports = function (defaults) {
// Stop: Normalize
app.import('node_modules/normalize.css/normalize.css');
app.import('node_modules/simplemde/debug/simplemde.css');
// 'dem Styles
// import codemirror + simplemde styles rather than lazy-loading so that
// our overrides work correctly
app.import('node_modules/simplemde/dist/simplemde.min.css');
// 'dem Scripts
app.import('node_modules/google-caja-bower/html-css-sanitizer-bundle.js');
app.import('node_modules/keymaster/keymaster.js');
app.import('node_modules/@tryghost/mobiledoc-kit/dist/amd/mobiledoc-kit.js');
app.import('node_modules/@tryghost/mobiledoc-kit/dist/amd/mobiledoc-kit.map');
app.import('node_modules/simplemde/debug/simplemde.js');
app.import('node_modules/reframe.js/dist/noframe.es.js', {
using: [
{transformation: 'es6', as: 'noframe.js'}
@ -148,6 +184,7 @@ module.exports = function (defaults) {
// that tests don't break when running via http://localhost:4200/tests
if (app.env === 'development') {
app.import('vendor/codemirror/lib/codemirror.js', {type: 'test'});
app.import('vendor/simplemde/debug/simplemde.js', {type: 'test'});
}
return app.toTree();