Search Party’s Millennial Horror Goes From Psychological to Physical
ByRoxana Hadadi,
a Vulture TV critic who also covers film and pop culture
Photo: HBO Max
Spoilers ahead for the conclusion of Search Party.
In 2017, when speaking with Vulture’s Devon Ivie about the second season of Search Party, series co-creators Sarah-Violet Bliss, Charles Rogers, and Michael Showalter listed an array of pop-culture influences for their millennial-focused mystery. Amid the art stuff (photographer Robert C. Wiles, painter Wassily Kandinsky) and the true-crime stuff (Dateline) was a certain through line: Alfred Hitchcock, Roman Polanski, and The Silence of the Lambs — do you sense a trend?
Search Party’s DNA has contained a certain amount of horror from the beginning of the disappearance-and-death saga, and in its final ten episodes that dropped on HBO Max on January 7, that subtext became the whole damn text. Search Party has always been a figurative exploration of millennial dystopia: unemployment and underemployment, hollow identities and missing selves, aimlessness and emptiness. And its transformation of those existential concerns into the literal end of the world in its concluding season seems as fated as Jeff Goldblum playing an evil tech bro.
When Search Party premiered in 2016 on TBS, its premise was somewhat straightforward. Twenty-something Dory Sief (Alia Shawkat), unfulfilled by her dead-end job and bored in her relationship with the dopey, ukulele-playing Drew Gardner (John Reynolds), threw herself into investigating the disappearance of college acquaintance Chantal Witherbottom (Clare McNulty). Neither Drew nor Dory’s other friends from college — aspiring actress Portia Davenport (Meredith Hagner) and nonprofit creator Elliott Goss (John Early) — really cared about the forgettable Chantal, but they went along with Dory’s increasingly obsessive quest because, well, they had nothing better to do. The four were bumbling, clumsy, self-obsessed, and un-self-aware — and incredibly sharply written. Each of them was looking for meaning, and none was anything close to happy.
As the season’s mystery became drenched in tension and paranoia, episodes ended often on cliffhanger moments by design, Showalter explained at a South by Southwest panel in 2016: “We want people to question, to speculate, to guess at what’s happening.” Alongside that descent into strangeness, Shawkat’s Dory revealed herself to be an increasingly unreliable figure, capable of convincing herself and her friends of nearly anything. Was she a good person making mistakes or a bad person feeding off other people’s attention? Was she trying to save Chantal for Chantal or for herself?
Early reviews focused on both the hipster-ness of it all and the series’ flirtation with subterfuge and menace. “It’s possessed of a dark sense of humor and an even darker sense of when to yank the rug out from under its characters,” wrote Emily VanDerWerff for Vox. Matt Zoller Seitz, who called it one of the “best shows of the year” in his Vulture review, seemingly anticipated where the series was going: “There’s an even deeper level to this series, something on the order of an existential quest, a long journey into the heroine’s emotional interior … Dory keeps encountering women who seem to reflect shards of her own scattered, numbed psyche — in particular her fear that she’s either imagining a lot of this or that she’s going insane.” That particular kind of woman has a long history throughout various genres. She is the figure Vulture’s Angelica Jade Bastién calls the “madwoman,” and Shawkat has transformed Dory into one of TV’s most uncontainably charismatic, deeply awful madwomen over and over again.
Through noir, courtroom drama, and thriller — genres Search Party adopted in seasons two, three, and four, respectively — Shawkat fine-tunes her character in relation to the tropes, rules, and boundaries of those narrative categories: Dory as a femme fatale, smirking through blood-red lipstick in her booking photo; Dory as an innocent woman, wearing Velma-like turtlenecks and prim skirts to court; Dory as an abductee and brainwashing victim with a jarring contrast between her forcibly shaved head and her docile voice. And in the final season, as Dory is plagued by visions of an apocalyptic future she is certain only she can disrupt, she pulls off another metamorphosis: into a cult leader whose actions cause the very zombie uprising and widespread devastation she foresaw. Dory has always considered herself a survivor, and she is. But Dory has never been a hero, and her ultimate positioning as both a villain whose delusions affect the entire world and a “final girl” who outlives dire circumstances help Search Party pull off its ultimate genre reimagining: horror.
The world of Search Party has always been defined by specific kinds of fear. After Dory, Drew, Portia, and Elliott kill private investigator Keith Powell (Ron Livingston), bury his body, and lie about the crime, Dory is haunted by visions of Keith’s reanimated corpse, while Elliott is so guilt-ridden that his hair falls out and he develops a full-body rash. The friends’ concern about what could happen to them if the truth gets out causes them to lie, sabotage, and blackmail others, and Dory — in a moment of rage that indicates her spontaneity when up against a wall — kills someone else to contain the secret.
But as the audience, we don’t share their fear of them being found out; in all honesty, facing some kind of punishment might actually be good for the foursome, who keep stumbling into increasingly precarious, soul-deadening situations. (Insert “These damn kids!” meme here.) During the second through fourth seasons, a dissociative Dory grows ever more smug about her crime, Drew lies to a new girlfriend about his identity, Portia agrees to star as Dory in a trashy movie about Keith’s death, and Elliott steps into the footsteps of Milo Yiannopoulos and hosts a politically conservative talk show at odds with his liberal beliefs as a gay man. Search Party’s willingness to experiment with form doesn’t belie its guiding ideology about the unique obstacles and peculiarities of the millennial experience and the discomfit that pervades it.
The difficulty of making new friends or starting new relationships keeps us tied to people we might no longer like let alone love. Anxiety about not being able to pay our bills pushes us into jobs that don’t align with our values. The desire for life finally to happen — maybe when student loans are paid off, maybe when enough money is scraped together for a down payment on a home, maybe when a decision is made on marriage and kids — makes us particularly susceptible to the promise of a magic pill that would solve all our problems. The sense of dread built by these everyday concerns already permeated Search Party for four seasons before the final season arrived; courage and accountability are proactive qualities, and Dory et al. do not have them. “Adults don’t care about making a difference … To not changing the damn world!” Drew, Portia, and Elliott toast at a dinner party in the fifth-season premiere, “Genesis.” (All the episodes in season five have names inspired by the Old and New Testaments, arguably the scariest books of all time.) When the first zombie appears in episode six, “The Gospel of Judas,” it’s almost a relief. Finally, a definitive, distinct purpose for these wayward millennials: Stay alive.
Photo: HBO Max
If the man who made Psycho and The Birds, the criminal who made Rosemary’s Baby, and the connection between Dr. Hannibal Lecter and FBI trainee Clarice Starling guided the early seasons of Search Party, then the Terminator franchise, The Omen, Stephen King, and George A. Romero cast their shadows over the series’ conclusion as the horror goes from psychological to physical. While Dory becomes a cult leader with an immaculate wardrobe, gold-painted fingers, and a message about how her followers should end their lives to reach enlightenment (“I died for 37 seconds … I did it, and now more than anything, I want you to do it”), Chantal reappears, tumbles down a QAnon-like tunnel of conspiracy theories, and emerges as a Sarah Connor–like figure, aware that the world will one day be in great danger. Chantal’s warnings, yelled alongside Kathy Griffin’s Liquorice Montague on the streets of New York, are ignored. But millions of followers and Goldblum’s tech billionaire, Tunnel Quinn, flock to Dory’s Instagram-issued suggestion that everyone should actually die in order to authentically live. It’s an ideology not so different from the ones believed by the people who died by suicide as part of Peoples Temple or Heaven’s Gate, but it spreads far and wide thanks to the social-media influencers who take up Dory’s mantle.
In the same way that no one in Midnight Mass says the word vampire, no one in Search Party says zombie until it’s too late: Dory’s mass-produced pills that look like jelly beans spark a bloody cannibalism spree that eventually affects the whole world. Blood splatter, grotesque makeup, and shaky camerawork build an array of action set pieces that make the undead danger real. Portia and Elliott escape a laser-tag arcade after Dory’s acolytes attack them; a crowd of fans cheers on Dory and then tries to rip her apart. And in a frantic finale, the four friends run for their lives from Elliott’s husband, Marc (Jeffery Self, whose line delivery of “Wet, wet, wet, wet, wet, wet, wet” is a revelation) and their genetically engineered son, Aspen (Kayden Koshelev), before Chantal appears with a flamethrower to save them. Dory as humanity’s destroyer and Chantal as its savior make for a thoughtful switcheroo, and Chantal ends up the only character who wrestles the last word away from Dory: “You always had delusions of grandeur.”
Photo: HBO Max
Earlier in the season, Aspen’s Damien Thorn–esque qualities, including his failed attempts to kill his fathers and his successful drowning of the pool boy (Julio Torres) who wouldn’t get him an ice cream, seemed like the greatest threat the friends might face. Aspen’s robotic mannerisms and cool menace felt like a parable about the hazards of a quick-fix solution to parenthood and of buying love rather than earning it. The same goes for Portia, who says “I would love to take something that could, like, fix me,” and who submits Dory to Munchausen syndrome by proxy (and drinks her bathwater) to keep Dory close to her. Sure, the zombies are bad. Yet as Search Party’s narrative sprawls in its back half, both “defective kid” Aspen and Portia are the most poignant indicators of the series’ broader warning against living one’s life as a series of shortcuts that end up hurting other people: the longing, the vulnerable, and the unfulfilled. What could be more horrifying or more monstrous than that?
“The darker it went, and the more dangerous … It really gets gruesome and scary, but all of those moments actually made the comedy more specific and more funny because the contrast makes the show even stronger,” said Lilly Burns, who produced the first three seasons of Search Party, at that SXSW panel in 2016. Four seasons later, Search Party fulfills the millennial ennui of its initial premise with the only way the series could have ended: this generation’s nightmares made horrifyingly real. Self-appointed saviors of humanity who exploit us, Big Pharma companies who poison us, partners who betray us, children who hate us, a public-health emergency that results in strangers trying to kill us. And equally fitting is the mantra of forced acceptance that Drew says as he, his now-wife, Dory, Portia, and Elliott — only ever-so-slightly changed and still as codependent as ever — walk past another collection of missing-persons signs: Well, it is what it is.
By submitting your email, you agree to our
Terms and Privacy Notice
and to receive email correspondence from us. This site is protected by reCAPTCHA and the Google
Privacy Policy and
Terms of Service apply.
or
Already a subscriber?
What is your email?
This email will be used to sign into all New York sites. By submitting your email, you agree to our Terms and Privacy Policy and to receive email correspondence from us.
Password must be at least 8 characters and contain:
Lower case letters (a-z)
Upper case letters (A-Z)
Numbers (0-9)
Special Characters (!@#$%^&*)
This password will be used to sign into all New York sites. By submitting your email, you agree to our Terms and Privacy Policy and to receive email correspondence from us.
You’re in!
As part of your account, you’ll receive occasional updates and offers from New York, which you can opt out of anytime.
or
Already a subscriber?
What is your email?
This email will be used to sign into all New York sites. By submitting your email, you agree to our Terms and Privacy Policy and to receive email correspondence from us.
Password must be at least 8 characters and contain:
Lower case letters (a-z)
Upper case letters (A-Z)
Numbers (0-9)
Special Characters (!@#$%^&*)
This password will be used to sign into all New York sites. By submitting your email, you agree to our Terms and Privacy Policy and to receive email correspondence from us.
You’re in!
As part of your account, you’ll receive occasional updates and offers from New York, which you can opt out of anytime.
Already a subscriber?
Already a subscriber?
`;
// integrate Sub(x) scripts and elements
if (hostname !== 'subs.nymag.com') { // do not integrate on this subdomain
document.head.appendChild(trackingScript);
document.body.insertAdjacentHTML('beforeend', subXAnimationElements);
}
There was an error processing the request. Please try again later."}).catch(e=>console.error("Error verifying email: ",e)))(r.querySelector(".content"),o.bannerCTAVerification)})):(l.remove(),s.remove()),o.dismissable||n.remove(),o.useAlertIcon||a.remove(),r.classList.add("show"),n.addEventListener("click",()=>{u(),r.classList.remove("show")})}else r.remove()}});
}, {"1":1,"6":6,"12":12,"35":35,"40":40}];
window.modules["global-nav.client"] = [function(require,module,exports){"use strict";const dom=require(3),auth=require(12),signInButton=dom.find(".user-signin"),signOutButton=dom.find(".user-signout"),globalNav=dom.find('[class^="global-nav"]'),body=dom.find("body"),dropdownItems=dom.findAll(".dropdown-wrap"),gtm=require(1),appendLandingPageParams=require(136),pageUri=require(124).getPageUri(),subscriptionPromoLinks=dom.findAll(".persist-params"),searchString=window.location.search||"";function closeDropdowns(e){let n=globalNav.querySelectorAll(".dropdown.open");dropdownItems.forEach(function(t){let o=t.querySelector(".dropdown");!n||t.contains(e.target)&&27!==e.keyCode||o.classList.remove("open")})}function gtmSendReport(e,n,t){let o={eventCategory:"ecommerce",eventAction:"componentClick",brand:e,dimension23:"global-nav",list:pageUri,pageZone:"header",variant:"nav-link"};"global-nav-link"===t&&(o.eventLabel=n.href),gtm.reportNow(o)}function updateElementTargetUrlsIfQueryStrings(e){if(searchString){const n=new URLSearchParams(searchString);let t=e.href;if(t.includes("?")){const o=t.split("?"),i=new URLSearchParams(o[1]);for(let e of n.entries())i.set(e[0],e[1]);t=`${o[0]}?${i.toString()}`,e.href=t}else e.href=`${t}?${n.toString()}`}}function init(e){const n=e.querySelectorAll(".to-landing-page");window.addEventListener("auth:init",()=>{signInButton.addEventListener("click",function(e){e.preventDefault(),auth.showEmbeddedLoginFlow("top navigation")}),signOutButton.addEventListener("click",function(e){e.preventDefault(),gtmSendReport("Sign Out",e.target,"user-info-link"),auth.logout()}),auth.isAuthenticated()&&e.classList.add("signed-in"),auth.isSubscriber()&&e.classList.add("subscribed"),e.querySelectorAll(".user-link").forEach(e=>{e.classList.add("active")}),subscriptionPromoLinks.forEach(e=>{updateElementTargetUrlsIfQueryStrings(e)}),appendLandingPageParams(n)})}dropdownItems.forEach(function(e){e.addEventListener("click",function(){e.querySelector(".dropdown").classList.toggle("open")})}),body.addEventListener("click",closeDropdowns),document.addEventListener("keydown",closeDropdowns),globalNav.addEventListener("click",function(e){let n=e.target;n.classList.contains("global-nav-track")&>mSendReport(n.text,n,"global-nav-link")}),module.exports=init;
}, {"1":1,"3":3,"12":12,"124":124,"136":136}];
window.modules["aaa-module-mounting.legacy"] = [function(require,module,exports){"use strict";const _pickBy=require(221),_each=require(408),Fingerprint2=require(407),DS=require(406),Eventify=require(246);function registerGlobals(){window.DS=DS,window.Eventify=Eventify,window.Fingerprint2=Fingerprint2,DS.value("Eventify",Eventify),DS.value("Fingerprint2",Fingerprint2),DS.value("$document",window.document),DS.value("$window",window)}function mountDollarSliceComponents(){DS.service("components",["$document","$module",function(e,n){var o=_pickBy(n.definitions,e=>e.providerStrategy===n.providers.controller),r=Object.keys(o);function t(e){return o=>{try{n.get(e,o)}catch(e){logMountError(o,e)}}}_each(r,n=>{var o=e.querySelectorAll('[data-uri*="/_components/'+n+'/"]'),r=e.querySelectorAll('[data-uri$="/_components/'+n+'"]');_each(o,t(n)),_each(r,t(n))}),this.components=r}]),DS.get("components")}function logMountError(e,n){const o=e.outerHTML.slice(0,e.outerHTML.indexOf(e.innerHTML));console.error("Error attaching controller to "+o,n)}registerGlobals(),"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{mountDollarSliceComponents()}):mountDollarSliceComponents();
}, {"221":221,"246":246,"406":406,"407":407,"408":408}];
window.modules["ads.legacy"] = [function(require,module,exports){"use strict";const _map=require(118),_forEach=require(107),_isString=require(268),_intersectionWith=require(409),_isEqual=require(274),_each=require(408),_debounce=require(182),_sortBy=require(205),page=require(124),visit=require(114);DS.service("adService",["Eventify","$cid","$document","$window",function(e,t,a,i){var o,n,s,r,d,c,u,l,g={},p=this,h=[],f=visit.getQueryParamsObject(["utm_campaign"]),m=document.querySelector('script[data-type="ad-a9"]'),b=[],w=!1,v=[],y=document.querySelector('script[data-name="ad-doubleverify"]');document.querySelector('script[data-name="concert-ads"]')||(i.NYM={},i.NYM.analytics={},i.NYM.analytics.adStartTime=i.performance.now(),i.googletag=i.googletag||{},i.googletag.cmd=i.googletag.cmd||[],u=i.googletag,(m||y)&&(i.googletag.cmd=i.googletag.cmd||[],i.googletag.cmd.push(function(){i.googletag.pubads().disableInitialLoad()})),m&&(l=i.setInterval(function(){void 0!==window.apstag&&void 0!==window.apstag.timeout&&(i.clearInterval(l),window.apstag.cleared=!0,l=null)},10),setTimeout(function(){l&&(i.clearInterval(l),i.googletag.pubads().refresh(),window.apstag||console.log("MESSAGE: Timeout for A9 load exceeded, aborting"))},500)),y&&(b.push(new Promise(function(e){w?e():v.push(e)})),c=i.setTimeout(T,2500)),o=function(e){var t,a,o=e.data,n=[];return o.loaded?e:(o.loaded=!0,t=null,(t=o.sizes?u.defineSlot(o.name,o.sizes,o.id).addService(u.pubads()):u.defineOutOfPageSlot(o.name,o.id).addService(u.pubads())).setTargeting("adid",o.id),f.hasOwnProperty("utm_campaign")&&t.setTargeting("utmcamp",f.utm_campaign),a=p.getAdCount(o.label),t.setTargeting("label",o.label+"_"+o.site+"-"+a),u.display(o.id),u.pubads().addEventListener("slotOnload",function(){i.NYM.analytics.firstAdLoadTime||(i.NYM.analytics.firstAdLoadTime=i.performance.now(),i.NYM.analytics.firstAdLoadLabel=e.data.label)}),n=_(o),Promise.all(b).then(function(){n?window.apstag&&window.apstag.cleared?window.apstag.fetchBids({slots:[n],timeout:window.apstag.timeout},function(){u.cmd.push(function(){window.apstag.setDisplayBids(),u.pubads().refresh([t],{changeCorrelator:!1})})}):y&&u.pubads().refresh([t],{changeCorrelator:!1}):u.pubads().refresh([t],{changeCorrelator:!1})}),e.slot=t,e)},n=function(e){var a,i,o,n=t(),s=e.getAttribute("data-name"),r=e.getAttribute("data-sizes"),d=e.getAttribute("data-label"),c=e.getAttribute("data-site");n=e.id,r&&r.length?(r=r.split(","),a=[],_map(r,function(e){e=e.split("x"),i=parseInt(e[0]),o=parseInt(e[1]),a.push([i,o])})):(e.classList.add("oop"),a=!1),this.data={id:n,name:s,sizes:a,loaded:!1,label:d,site:c},g[n]=this},r=function(e){u.cmd.push(function(){var t=o(e);g[e.data.id]=t})},s=function(e){var t=[];e.slot?(t=_(e))&&window.apstag&&window.apstag.cleared&&window.apstag.fetchBids({slots:[t],timeout:window.apstag.timeout},function(){u.cmd.push(function(){window.apstag.setDisplayBids(),u.pubads().refresh([e.slot],{changeCorrelator:!1})})}):e&&r(e)},u.cmd.push(function(){var e,t,o,n=page.getMeta("article:tag"),s=page.getMeta("author"),r=i.location.href,d=(e=a.head.querySelector(".head-gtm"),t=a.body.querySelector(".gtm"),e&&"top"===e.getAttribute("data-gtm")?"gtmtop":t&&"bottom"===t.getAttribute("data-gtm")?"gtmbottom":"");o=[],_forEach([n,s,d],function(e){_forEach(e.split(","),function(e){(e=e.trim().toLowerCase().replace(/\s/g,"-").replace(/\'|\’/g,"")).length&&o.push(e)})}),u.pubads().setTargeting("kw",o),u.pubads().setTargeting("entry_group",o),r=r.slice(r.lastIndexOf("/")+1),u.pubads().setTargeting("pn",r),u.companionAds().setRefreshUnfilledSlots(!0),u.pubads().enableAsyncRendering(),u.enableServices()}),this.load=r,this.create=function(e){return new n(e)},this.refresh=function(e){var t;_isString(e)?(t=this.getById(e),s(t)):s(e)},this.remove=function(e){var t=e.data.id;a.getElementById(t).innerHTML=""},this.getAdCount=function(e){var t,a=0,i=Object.keys(g);return _each(i,function(i){(t=g[i]).data.loaded&&t.data.label===e&&a++}),a},this.getById=function(e){return g[e]},d=_debounce(function(){var e={TopLeaderboard:1,RightColTopMPU:2,outOfPage:99,"homepageTakeover/TopLeaderboard":1},t=_sortBy(h,function(t){return e[t.data.label]||10});_forEach(t,function(e){return e.data.sizes?r(e):i.setTimeout(function(){r(e)},2e3)}),y&&window.PQ.cmd.push(()=>{try{window.PQ.loadSignals(["ids","bsc","vlp"],T)}catch(e){T(),console.error(`There has been an error loading Double Verify signals: ${e}`)}}),h=[]},10),this.addToPageLoadQueue=function(e){h.push(e),d()});function _(e){var t,a=e.sizes;return a=_intersectionWith(a,[[970,250],[970,90],[728,90],[300,600],[300,250],[320,100],[320,50]],_isEqual),e.sizes&&e.sizes.length&&(t={slotID:e.id,sizes:a,slotName:e.label}),t}function T(){i.clearTimeout(c),w=!0,_forEach(v,function(e){e()})}}]);
}, {"107":107,"114":114,"118":118,"124":124,"182":182,"205":205,"268":268,"274":274,"408":408,"409":409}];
window.modules["cid.legacy"] = [function(require,module,exports){"use strict";DS.service("$cid",function(){var r=Math.floor(100*Math.random());return function(){return"cid-"+ ++r}});
}, {}];
window.modules["client.legacy"] = [function(require,module,exports){"use strict";require("cid.legacy"),require("ads.legacy"),require("facebook.legacy"),require("aaa-module-mounting.legacy");
}, {"cid.legacy":"cid.legacy","aaa-module-mounting.legacy":"aaa-module-mounting.legacy","ads.legacy":"ads.legacy","facebook.legacy":"facebook.legacy"}];
window.modules["facebook.legacy"] = [function(require,module,exports){"use strict";DS.service("facebook",[function(){this.fb=function(i){window.FB&&window.FB[i].apply(this,Array.prototype.slice.call(arguments,1))}}]);
}, {}];
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o typeof key === 'string' && key.match(/\.legacy$/)).forEach(key => window.require(key));
}
function tryToMount(fn, el, name) {
try {
fn(el); // init the controller
} catch (e) {
const elementTag = el.outerHTML.slice(0, el.outerHTML.indexOf(el.innerHTML));
console.error(`Error initializing controller for "${name}" on "${elementTag}"`, e);
}
}
/**
* mount client.js component controllers
*/
function mountComponentModules() {
Object.keys(window.modules).filter(key => typeof key === 'string' && key.match(/\.client$/)).forEach(key => {
let controllerFn = window.require(key);
if (typeof controllerFn === 'function') {
const name = key.replace('.client', ''),
instancesSelector = `[data-uri*="_components/${name}/"]`,
defaultSelector = `[data-uri$="_components${name}"]`,
instances = document.querySelectorAll(instancesSelector),
defaults = document.querySelectorAll(defaultSelector);
for (let el of instances) {
tryToMount(controllerFn, el, name);
}
for (let el of defaults) {
tryToMount(controllerFn, el, name);
}
}
});
}
// Make sure that a `window.process.env.NODE_ENV` is available in the client for any dependencies,
// services, or components that could require it
// note: the `` value is swapped for the actual environment variable in /lib/cmd/compile/scripts.js
window.process = window.process || {};
window.process.env = window.process.env || {};
if (!window.process.env.NODE_ENV) {
window.process.env.NODE_ENV = '';
}
// note: legacy controllers that require legacy services (e.g. dollar-slice) must
// wait for DOMContentLoaded to initialize themselves, as the files themselves must be mounted first
mountLegacyServices();
mountComponentModules();
// ]]