diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js
index d2810049e6cb9e5c639f13d07ef7b33ec15cb286..e5deab196954c224cb81501a37863e4c524134e1 100644
--- a/app/assets/javascripts/content_editor/services/markdown_serializer.js
+++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js
@@ -28,14 +28,26 @@ import {
   renderTableCell,
   renderTableRow,
   renderOrderedList,
-  renderHeading,
   renderHTMLNode,
-  renderContent,
   renderBulletList,
   renderReference,
   renderReferenceLabel,
   preserveUnchanged,
 } from './serialization_helpers';
+import descriptionList from './serializer/description_list';
+import descriptionItem from './serializer/description_item';
+import details from './serializer/details';
+import detailsContent from './serializer/details_content';
+import emoji from './serializer/emoji';
+import footnoteDefinition from './serializer/footnote_definition';
+import footnoteReference from './serializer/footnote_reference';
+import frontmatter from './serializer/frontmatter';
+import figure from './serializer/figure';
+import figureCaption from './serializer/figure_caption';
+import heading from './serializer/heading';
+import horizontalRule from './serializer/horizontal_rule';
+import listItem from './serializer/list_item';
+import loading from './serializer/loading';
 
 const defaultSerializerConfig = {
   marks: {
@@ -66,61 +78,22 @@ const defaultSerializerConfig = {
     [extensions.Diagram.name]: diagram,
     [extensions.CodeSuggestion.name]: codeSuggestion,
     [extensions.DrawioDiagram.name]: drawioDiagram,
-    [extensions.DescriptionList.name]: renderHTMLNode('dl', true),
-    [extensions.DescriptionItem.name]: (state, node, parent, index) => {
-      if (index === 1) state.ensureNewLine();
-      renderHTMLNode(node.attrs.isTerm ? 'dt' : 'dd')(state, node);
-      if (index === parent.childCount - 1) state.ensureNewLine();
-    },
-    [extensions.Details.name]: renderHTMLNode('details', true),
-    [extensions.DetailsContent.name]: (state, node, parent, index) => {
-      if (!index) renderHTMLNode('summary')(state, node);
-      else {
-        if (index === 1) state.ensureNewLine();
-        renderContent(state, node);
-        if (index === parent.childCount - 1) state.ensureNewLine();
-      }
-    },
-    [extensions.Emoji.name]: (state, node) => {
-      const { name } = node.attrs;
-
-      state.write(`:${name}:`);
-    },
-    [extensions.FootnoteDefinition.name]: preserveUnchanged((state, node) => {
-      state.write(`[^${node.attrs.identifier}]: `);
-      state.renderInline(node);
-      state.ensureNewLine();
-    }),
-    [extensions.FootnoteReference.name]: preserveUnchanged({
-      render: (state, node) => {
-        state.write(`[^${node.attrs.identifier}]`);
-      },
-      inline: true,
-    }),
-    [extensions.Frontmatter.name]: preserveUnchanged((state, node) => {
-      const { language } = node.attrs;
-      const syntax = {
-        toml: '+++',
-        json: ';;;',
-        yaml: '---',
-      }[language];
-
-      state.write(`${syntax}\n`);
-      state.text(node.textContent, false);
-      state.ensureNewLine();
-      state.write(syntax);
-      state.closeBlock(node);
-    }),
-    [extensions.Figure.name]: renderHTMLNode('figure'),
-    [extensions.FigureCaption.name]: renderHTMLNode('figcaption'),
+    [extensions.DescriptionList.name]: descriptionList,
+    [extensions.DescriptionItem.name]: descriptionItem,
+    [extensions.Details.name]: details,
+    [extensions.DetailsContent.name]: detailsContent,
+    [extensions.Emoji.name]: emoji,
+    [extensions.FootnoteDefinition.name]: footnoteDefinition,
+    [extensions.FootnoteReference.name]: footnoteReference,
+    [extensions.Frontmatter.name]: frontmatter,
+    [extensions.Figure.name]: figure,
+    [extensions.FigureCaption.name]: figureCaption,
     [extensions.HardBreak.name]: preserveUnchanged(renderHardBreak),
-    [extensions.Heading.name]: preserveUnchanged(renderHeading),
-    [extensions.HorizontalRule.name]: preserveUnchanged(
-      defaultMarkdownSerializer.nodes.horizontal_rule,
-    ),
+    [extensions.Heading.name]: heading,
+    [extensions.HorizontalRule.name]: horizontalRule,
     [extensions.Image.name]: image,
-    [extensions.ListItem.name]: preserveUnchanged(defaultMarkdownSerializer.nodes.list_item),
-    [extensions.Loading.name]: () => {},
+    [extensions.ListItem.name]: listItem,
+    [extensions.Loading.name]: loading,
     [extensions.OrderedList.name]: preserveUnchanged(renderOrderedList),
     [extensions.Paragraph.name]: preserveUnchanged(defaultMarkdownSerializer.nodes.paragraph),
     [extensions.HTMLComment.name]: (state, node) => {
diff --git a/app/assets/javascripts/content_editor/services/serialization_helpers.js b/app/assets/javascripts/content_editor/services/serialization_helpers.js
index 194ecc79a2012860370111d0d14002b137abf825..b44e600b2f9359133061127e8dfe5300506c04dd 100644
--- a/app/assets/javascripts/content_editor/services/serialization_helpers.js
+++ b/app/assets/javascripts/content_editor/services/serialization_helpers.js
@@ -1,5 +1,4 @@
 import { uniq, omit, isFunction } from 'lodash';
-import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
 
 const defaultAttrs = {
   td: { colspan: 1, rowspan: 1, colwidth: null, align: 'left' },
@@ -337,12 +336,6 @@ export function renderHardBreak(state, node, parent, index) {
   }
 }
 
-export function renderHeading(state, node) {
-  if (state.options.skipEmptyNodes && !node.childCount) return;
-
-  defaultMarkdownSerializer.nodes.heading(state, node);
-}
-
 const expandPreserveUnchangedConfig = (configOrRender) =>
   isFunction(configOrRender)
     ? { render: configOrRender, overwriteSourcePreservationStrategy: false, inline: false }
diff --git a/app/assets/javascripts/content_editor/services/serializer/description_item.js b/app/assets/javascripts/content_editor/services/serializer/description_item.js
new file mode 100644
index 0000000000000000000000000000000000000000..842c84f910e79d5394ba209c1efbb1b930d09169
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/description_item.js
@@ -0,0 +1,9 @@
+import { renderHTMLNode } from '../serialization_helpers';
+
+const descriptionItem = (state, node, parent, index) => {
+  if (index === 1) state.ensureNewLine();
+  renderHTMLNode(node.attrs.isTerm ? 'dt' : 'dd')(state, node);
+  if (index === parent.childCount - 1) state.ensureNewLine();
+};
+
+export default descriptionItem;
diff --git a/app/assets/javascripts/content_editor/services/serializer/description_list.js b/app/assets/javascripts/content_editor/services/serializer/description_list.js
new file mode 100644
index 0000000000000000000000000000000000000000..a8262930c68b610fe8d3efb452a7cec86c25486d
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/description_list.js
@@ -0,0 +1,5 @@
+import { renderHTMLNode } from '../serialization_helpers';
+
+const descriptionList = renderHTMLNode('dl', true);
+
+export default descriptionList;
diff --git a/app/assets/javascripts/content_editor/services/serializer/details.js b/app/assets/javascripts/content_editor/services/serializer/details.js
new file mode 100644
index 0000000000000000000000000000000000000000..af3c9499b805a513f7ad14257fdf5f853a238b7b
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/details.js
@@ -0,0 +1,5 @@
+import { renderHTMLNode } from '../serialization_helpers';
+
+const details = renderHTMLNode('details', true);
+
+export default details;
diff --git a/app/assets/javascripts/content_editor/services/serializer/details_content.js b/app/assets/javascripts/content_editor/services/serializer/details_content.js
new file mode 100644
index 0000000000000000000000000000000000000000..f799ec34966c4f91f1ca538e8960b3a44e004bdb
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/details_content.js
@@ -0,0 +1,12 @@
+import { renderContent, renderHTMLNode } from '../serialization_helpers';
+
+const detailsContent = (state, node, parent, index) => {
+  if (!index) renderHTMLNode('summary')(state, node);
+  else {
+    if (index === 1) state.ensureNewLine();
+    renderContent(state, node);
+    if (index === parent.childCount - 1) state.ensureNewLine();
+  }
+};
+
+export default detailsContent;
diff --git a/app/assets/javascripts/content_editor/services/serializer/emoji.js b/app/assets/javascripts/content_editor/services/serializer/emoji.js
new file mode 100644
index 0000000000000000000000000000000000000000..6983411ebdc38ee04ce015965012d86660bcb51a
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/emoji.js
@@ -0,0 +1,7 @@
+const emoji = (state, node) => {
+  const { name } = node.attrs;
+
+  state.write(`:${name}:`);
+};
+
+export default emoji;
diff --git a/app/assets/javascripts/content_editor/services/serializer/figure.js b/app/assets/javascripts/content_editor/services/serializer/figure.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a2e08f190207a175e8ca2a9b6cf93bd38b171d6
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/figure.js
@@ -0,0 +1,5 @@
+import { renderHTMLNode } from '../serialization_helpers';
+
+const figure = renderHTMLNode('figure');
+
+export default figure;
diff --git a/app/assets/javascripts/content_editor/services/serializer/figure_caption.js b/app/assets/javascripts/content_editor/services/serializer/figure_caption.js
new file mode 100644
index 0000000000000000000000000000000000000000..d55b6eab54255eb12d0dd80defdf9fc23dc80822
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/figure_caption.js
@@ -0,0 +1,5 @@
+import { renderHTMLNode } from '../serialization_helpers';
+
+const figureCaption = renderHTMLNode('figcaption');
+
+export default figureCaption;
diff --git a/app/assets/javascripts/content_editor/services/serializer/footnote_definition.js b/app/assets/javascripts/content_editor/services/serializer/footnote_definition.js
new file mode 100644
index 0000000000000000000000000000000000000000..28719ee808ca4ee1fb8f1362b6ba9ed634678c12
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/footnote_definition.js
@@ -0,0 +1,9 @@
+import { preserveUnchanged } from '../serialization_helpers';
+
+const footnoteDefinition = preserveUnchanged((state, node) => {
+  state.write(`[^${node.attrs.identifier}]: `);
+  state.renderInline(node);
+  state.ensureNewLine();
+});
+
+export default footnoteDefinition;
diff --git a/app/assets/javascripts/content_editor/services/serializer/footnote_reference.js b/app/assets/javascripts/content_editor/services/serializer/footnote_reference.js
new file mode 100644
index 0000000000000000000000000000000000000000..199c49a45ab02867b9adea1656095c74fcef7b1a
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/footnote_reference.js
@@ -0,0 +1,10 @@
+import { preserveUnchanged } from '../serialization_helpers';
+
+const footnoteReference = preserveUnchanged({
+  render: (state, node) => {
+    state.write(`[^${node.attrs.identifier}]`);
+  },
+  inline: true,
+});
+
+export default footnoteReference;
diff --git a/app/assets/javascripts/content_editor/services/serializer/frontmatter.js b/app/assets/javascripts/content_editor/services/serializer/frontmatter.js
new file mode 100644
index 0000000000000000000000000000000000000000..83cf0ebb56b221b32a1690ca897f441e11312801
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/frontmatter.js
@@ -0,0 +1,18 @@
+import { preserveUnchanged } from '../serialization_helpers';
+
+const frontmatter = preserveUnchanged((state, node) => {
+  const { language } = node.attrs;
+  const syntax = {
+    toml: '+++',
+    json: ';;;',
+    yaml: '---',
+  }[language];
+
+  state.write(`${syntax}\n`);
+  state.text(node.textContent, false);
+  state.ensureNewLine();
+  state.write(syntax);
+  state.closeBlock(node);
+});
+
+export default frontmatter;
diff --git a/app/assets/javascripts/content_editor/services/serializer/heading.js b/app/assets/javascripts/content_editor/services/serializer/heading.js
new file mode 100644
index 0000000000000000000000000000000000000000..fa710bb0747124efc958997299b8f991a236e4eb
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/heading.js
@@ -0,0 +1,10 @@
+import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
+import { preserveUnchanged } from '../serialization_helpers';
+
+const heading = preserveUnchanged((state, node) => {
+  if (state.options.skipEmptyNodes && !node.childCount) return;
+
+  defaultMarkdownSerializer.nodes.heading(state, node);
+});
+
+export default heading;
diff --git a/app/assets/javascripts/content_editor/services/serializer/horizontal_rule.js b/app/assets/javascripts/content_editor/services/serializer/horizontal_rule.js
new file mode 100644
index 0000000000000000000000000000000000000000..560dc3e124b73f0f513bb4c491faee9878255632
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/horizontal_rule.js
@@ -0,0 +1,6 @@
+import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
+import { preserveUnchanged } from '../serialization_helpers';
+
+const horizontalRule = preserveUnchanged(defaultMarkdownSerializer.nodes.horizontal_rule);
+
+export default horizontalRule;
diff --git a/app/assets/javascripts/content_editor/services/serializer/list_item.js b/app/assets/javascripts/content_editor/services/serializer/list_item.js
new file mode 100644
index 0000000000000000000000000000000000000000..cac00838b08653f701dc6650a4df4ad47f3b3a1c
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/list_item.js
@@ -0,0 +1,6 @@
+import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
+import { preserveUnchanged } from '../serialization_helpers';
+
+const listItem = preserveUnchanged(defaultMarkdownSerializer.nodes.list_item);
+
+export default listItem;
diff --git a/app/assets/javascripts/content_editor/services/serializer/loading.js b/app/assets/javascripts/content_editor/services/serializer/loading.js
new file mode 100644
index 0000000000000000000000000000000000000000..6df7fdd31fb52323959fea2019fa942176553c88
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/serializer/loading.js
@@ -0,0 +1,3 @@
+const loading = () => {};
+
+export default loading;