Opened 7 months ago
Last modified 12 days ago
#35371 assigned Bug
False positive in JS module aggregation export regex when an export declaration precedes an import declaration
Reported by: | Michael | Owned by: | Calvin Vu |
---|---|---|---|
Component: | contrib.staticfiles | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Calvin Vu | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
This regex from django/contrib/staticfiles/storage.py -> HashedFilesMixin -> _js_module_import_aggregation_patterns:
( ( r"""(?P<matched>export(?s:(?P<exports>[\s\{].*?))""" r"""\s*from\s*["'](?P<url>[./].*?)["']\s*;)""" ), """export%(exports)s from "%(url)s";""", ),
Can result in a matchobj like this:
> /home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py(225)converter() (Pdb) pp matchobj.re re.compile('(?P<matched>export(?s:(?P<exports>[\\s\\{].*?))\\s*from\\s*["\'](?P<url>[./].*?)["\']\\s*;)', re.IGNORECASE) (Pdb) pp matchobj.groupdict() {'exports': ' async function getTakeMessageDialog(a,t={}){const ' 'e=f();e.toggleAttribute("top",!0);const ' 'i=document.createElement("wc-take-message");for(i.toggleAttribute("caneditcontacts",a),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take ' 'a Message",confirm:"Submit"}),i.focus();;){if(!await ' 'e.waitClickedAction())return;if(!i.validate())continue;const ' 'n=await ' 'c.createTakeMessage(i.props);if(n.ok){e.close(),n.notifySuccess("Message ' 'taken");return}}}import w', 'matched': 'export async function getTakeMessageDialog(a,t={}){const ' 'e=f();e.toggleAttribute("top",!0);const ' 'i=document.createElement("wc-take-message");for(i.toggleAttribute("caneditcontacts",a),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take ' 'a Message",confirm:"Submit"}),i.focus();;){if(!await ' 'e.waitClickedAction())return;if(!i.validate())continue;const ' 'n=await ' 'c.createTakeMessage(i.props);if(n.ok){e.close(),n.notifySuccess("Message ' 'taken");return}}}import w from ' '"/static/skin/skin/x-field.min.c6fe58e9f403.css";', 'url': '/static/skin/skin/x-field.min.c6fe58e9f403.css'} (Pdb) matchobj.string 'var l=Object.defineProperty;var p=(a,t,e)=>t in a?l(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var o=(a,t,e)=>(p(a,typeof t!="symbol"?t+"":t,e),e);import*as r from"/static/jsapp/jsapp/dtmod.min.js";import*as c from"/static/comms/jsapp/fetcher.min.js";import*as g from"/static/jsapp/jsapp/ui.min.js";import*as m from"/static/jsapp/jsapp/formmod.min.js";import{createDialog as f} from "/static/wcapp/wcapp/wc-dialog.min.2f89ad88aab3.js";import{BaseComponent as h} from "/static/wcapp/jsapp/wc-base.min.425310100bce.js";class d extends h{init(){g.setupAutoHeight(this.get("MESSAGE")),this.initProps(!1)}setupEvents(){this.get("EDIT").onclick=this.setEditMode.bind(this,!0),this.get("CANCEL").onclick=this.setEditMode.bind(this,!1),this.get("SAVE").onclick=async()=>{if(!this.validate())return;(await c.updateTakeMessage(this._props.id,this.props)).ok&&this.setEditMode(!1)}}setEditMode(t){this.toggleAttribute("disabled",!t)}setNoAddContact(){const t=this.get("SEL_ADD_CONTACT").checked;this.toggleAttribute("noaddcontact",!t)}selectContactHandler(t){var e;((e=t.target)==null?void 0:e.getAttribute("name"))==="select_contact"&&this.setNoAddContact()}attributeChangedCallback(t,e,i){switch(t){case"disabled":this.setDisabled(i!==null);break}}set props(t){console.log(t),this._props=t;for(const e of Object.keys(t))switch(e){case"message":this.get("MESSAGE").value=t[e];break;case"createdUtc":this.get("TAKEN_AT").innerHTML=r.formatIsoStr(t[e],r.SHORT_DATETIME);break;case"userName":this.get("TAKEN_BY").innerHTML=t[e];break;case"recipientName":this.get("TAKEN_FOR").innerHTML=t[e];break;case"clientName":const i=t[e];t.client||(this.get("CLIENT_NAME").value=t[e],this.get("CLIENT_NAME").toggleAttribute("required",!0),this.get("CLIENT_NAME_LABEL").classList.remove("d:n"));break;case"client":const s=t[e];s&&(this.get("BADGE").props=s,this.get("BADGE").classList.remove("d:n"));break;case"contact":this.get("CONTACT").props=t[e]}}get props(){var i;return{client:(i=this._props.client)==null?void 0:i.id,clientName:this.get("CLIENT_NAME").value,message:this.get("MESSAGE").value,contact:this.get("CONTACT").props}}setDisabled(t){this.get("CONTACT").disabled=t,this.get("MESSAGE").disabled=t,this.get("CLIENT_NAME").disabled=t}validate(){const t=["CONTACT","MESSAGE"].map(e=>this.get(e));return this.get("CLIENT_NAME").classList.contains("d:n")||t.push(this.get("CLIENT_NAME")),m.manualClientValidation(t)}}o(d,"observedAttributes",["disabled"]),o(d,"properties",["props"]);export async function getTakeMessageDialog(a,t={}){const e=f();e.toggleAttribute("top",!0);const i=document.createElement("wc-take-message");for(i.toggleAttribute("caneditcontacts",a),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take a Message",confirm:"Submit"}),i.focus();;){if(!await e.waitClickedAction())return;if(!i.validate())continue;const n=await c.createTakeMessage(i.props);if(n.ok){e.close(),n.notifySuccess("Message taken");return}}}import w from "/static/skin/skin/x-field.min.c6fe58e9f403.css";import u from "/static/common/skin/cfm-heading.min.b8e21816b92c.css";const b=[w,u];d.initComponent(String.raw`<div id="MAIN" class="d:f f-d:c g:--gap"><div id="TAKEN_TABLE" class="d:g (w>768)g-t-c:repeat(6,auto) (w<768)g-t-c:auto_auto w:f-c g:8"><div x-field="label">By</div><div id="TAKEN_BY" class="m-r:16"></div><div x-field="label">At</div><div id="TAKEN_AT" class="m-r:16"></div><div x-field="label">For</div><div id="TAKEN_FOR"></div></div><div cfm-heading>Client</div><label id="CLIENT_NAME_LABEL" for="CLIENT_NAME" class="d:n d:f? a-i:c f-w:w g:8px_16px"><div x-field="label">Client Name</div><input id="CLIENT_NAME" x-field="widget tonal stadium" type="text" disabled></label><wc-badge id="BADGE" class="d:n w:256 max-w:100%"></wc-badge><div cfm-heading>Contact</div><wc-contact disabled id="CONTACT"></wc-contact><div class="d:f g:--gap f-w:w"><div class="d:f f-d:c g:--gap f-g:15"><label cfm-heading for="MESSAGE">Message</label><textarea id="MESSAGE" rows="4" x-field="widget tonal stadium" class="f-g:1" required disable-if-disabled></textarea></div></div><div class="f-s:i c:--red" show-if-enabled>Please note:<br>The recipient will not be notified or emailed again, and any memo\'s or contacts that were originally created from the message will remain as is.</div><div class="d:f? m-t:16 j-c:e a-i:c f-w:w g:16px_16px" show-if-canedit><wc-button id="EDIT" type="tonal" color="primary" show-if-disabled>EDIT</wc-button><wc-button id="CANCEL" type="tonal" color="bw" class="min-w:92" show-if-enabled>CANCEL</wc-button><wc-button id="SAVE" type="solid" color="secondary" class="min-w:92" show-if-enabled>SAVE</wc-button></div></div>\n`,String.raw`:host{display:block}\n*,*:before,*:after{box-sizing:border-box}\n::selection{color:var(--selection-fg, white);background:var(--selection-bg, #888)}\nsvg{vertical-align:bottom}\nsvg,img[src$=".svg"]{flex-shrink:0}\ntextarea{font-family:inherit}\n.a-i\\:c{align-items:center!important}\n.c\\:--red{color:var(--red)!important}\n.d\\:f{display:flex!important}\n.d\\:f\\?{display:flex}\n.d\\:g{display:grid!important}\n.d\\:n{display:none!important}\n.f-d\\:c{flex-direction:column!important}\n.f-g\\:1{flex-grow:1!important}\n.f-g\\:15{flex-grow:15!important}\n.f-s\\:i{font-style:italic!important}\n.f-w\\:w{flex-wrap:wrap!important}\n.g\\:--gap{gap:var(--gap)!important}\n.g\\:16px_16px{gap:16px 16px!important}\n.g\\:8{gap:8px!important}\n.g\\:8px_16px{gap:8px 16px!important}\n.j-c\\:e{justify-content:end!important}\n.m-r\\:16{margin-right:16px!important}\n.m-t\\:16{margin-top:16px!important}\n.max-w\\:100\\%{max-width:100%!important}\n.min-w\\:92{min-width:92px!important}\n.w\\:256{width:256px!important}\n.w\\:f-c{width:fit-content!important}\n@media (max-width:767.999px){.\\(w\\<768\\)g-t-c\\:auto_auto{grid-template-columns:auto auto!important}}\n@media (min-width:768.001px){.\\(w\\>768\\)g-t-c\\:repeat\\(6\\,auto\\){grid-template-columns:repeat(6,auto)!important}}\n:host{display:grid;grid-template-columns:minmax(100%,1024px)}\n:host(:not([disabled])) [show-if-disabled]{display:none!important}\n:host([disabled]) [show-if-enabled]{display:none!important}\n:host(:not([canedit])) [show-if-canedit]{display:none!important}\n`,b,"wc-message-taken",["wc-button","wc-select-client","wc-contact","wc-modal"]);\n'
From this Javascript file:
var r=Object.defineProperty;var p=(n,t,e)=>t in n?r(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var c=(n,t,e)=>(p(n,typeof t!="symbol"?t+"":t,e),e);import*as d from"/static/comms/jsapp/fetcher.min.js";import*as h from"/static/jsapp/jsapp/ui.min.js";import*as g from"/static/jsapp/jsapp/formmod.min.js";import{createDialog as f}from"/static/wcapp/wcapp/wc-dialog.min.js";import{BaseComponent as u}from"/static/wcapp/jsapp/wc-base.min.js";class l extends u{init(){this._setupPromise=this.setupContext(),h.setupAutoHeight(this.get("MESSAGE")),this.initProps(!1)}setupEvents(){this.get("SELECT_CLIENT").addEventListener("clientChanged",this.changeClientHandler.bind(this)),this.get("SELECT_CLIENT").addEventListener("clientCleared",this.clientClearedHandler.bind(this)),this.get("CONTACTS").addEventListener("click",this.clickButtonHandler.bind(this)),this.get("CONTACTS").addEventListener("change",this.selectContactHandler.bind(this))}setNoAddContact(){const t=this.get("SEL_ADD_CONTACT").checked;this.toggleAttribute("noaddcontact",!t)}selectContactHandler(t){var e;((e=t.target)==null?void 0:e.getAttribute("name"))==="select_contact"&&this.setNoAddContact()}attributeChangedCallback(t,e,i){switch(t){case"disabled":this.setDisabled(i!==null);break}}set props(t){this._props=t}get props(){const t=this.getAttribute("clientid");return{...this._props,client:t?parseInt(t):null,clientName:t?null:this.get("SELECT_CLIENT").pattern,recipient:parseInt(this.get("RECIPIENT").value),message:this.get("MESSAGE").value,contact:this.querySelectedContactEl().props,createMemo:this.get("CREATE_MEMO").checked,addContact:this.get("ADD_CONTACT").checked}}async setupContext(){this._context||(this._context=await this.getContext(),this.buildEmployees(this._context.employees),this.buildClients(this._context.clients))}async buildEmployees(t){if(this.get("RECIPIENT").firstElementChild)return;const e=t.map(s=>{const a=document.createElement("option");return a.value=s.pk,a.innerText=s.fullName,a});this.get("RECIPIENT").replaceChildren(...e);const i=Math.min(e.length,10);!this.hasAttribute("disabled")&&!this.hasAttribute("update")&&this.get("RECIPIENT").setAttribute("size",i),this.get("RECIPIENT").setAttribute("sizebak",i)}async buildClients(t){this.get("SELECT_CLIENT").props=t}async getContext(){if(this._context)return this._context;const t=await d.getContext();if(t.ok)return this._context=t.json,this._context}setDisabled(t){this.shadowRoot.querySelectorAll("[disable-if-disabled]").forEach(i=>i.toggleAttribute("disabled",t)),this.hasAttribute("update")&&this.get("RECIPIENT").toggleAttribute("disabled",!0);const e=this.get("RECIPIENT");this.get("RECIPIENT").hasAttribute("disabled")?e.removeAttribute("size"):e.setAttribute("size",e.getAttribute("sizebak"))}cloneChild(t,e){const i=this.get("CONTACT_TEMPLATE").content.cloneNode(!0).firstElementChild,s=i.querySelector("wc-contact");s.props=t;const a=i.querySelector('[name="select_contact"]'),o=i.querySelector("label");return a.id=`contact_${t.hash}`,o.setAttribute("for",a.id),s.disabled=!0,i}getContactOptions(){return this._contactOptions}selectContact(t){const e=this.get("CONTACTS").querySelector(`[data-hash="${t}"]`),i=e==null?void 0:e.querySelector('[name="contact"]');i&&(i.checked=!0)}setContact(t){t.hash?this.selectContact(t.hash):(this.get("NEW_CONTACT").props=t,this.get("ADD_CONTACT").checked=!0)}setContacts(t){this._contactOptions=t||[];const e=this._contactOptions.map((i,s)=>this.cloneChild(i,s));this.get("CONTACTS_SLOT").replaceChildren(...e)}setExistingClient(t){t?this.setAttribute("clientid",t):this.removeAttribute("clientid"),t||(this.get("SEL_ADD_CONTACT").checked=!0),t||(this.get("ADD_CONTACT").checked=!1),this.get("MESSAGE").autoHeight()}changeClientHandler(t){const e=t.detail.props;this.setExistingClient(e==null?void 0:e.id);const i=(e==null?void 0:e.hashedContacts)||[];this.setContacts(i)}enableEditContact(t,e){const i=e.querySelector("wc-contact");i.disabled=!t,e.querySelector('[data-button="edit"]').classList.toggle("d:n",t),e.querySelector('[data-button="cancel"]').classList.toggle("d:n",!t),e.querySelector('[data-button="save"]').classList.toggle("d:n",!t)}clickButtonHandler(t){const e=t.target.getAttribute("data-button");if(!e)return;t.stopPropagation();const i=t.target.closest(".js-main");switch(e){case"edit":this.enableEditContact(!0,i);break;case"cancel":this.enableEditContact(!1,i);break;case"save":this.updateContact(i);break}}clientClearedHandler(){this.setExistingClient(!1),this.setContacts([]),this.setNoAddContact()}querySelectedMainEl(){return this.get("CONTACTS").querySelector('[name="select_contact"]:checked').closest(".js-main")}querySelectedContactEl(){return this.querySelectedMainEl().querySelector("wc-contact")}focus(){this.get("SELECT_CLIENT").focus()}validate(){const t=["SELECT_CLIENT","RECIPIENT","MESSAGE"].map(e=>this.get(e));return g.manualClientValidation(t)}async updateContact(t){const e=parseInt(this.getAttribute("clientid")),i=t.querySelector("wc-contact"),a={contact:i.props},o=await d.clientUpdateContact(e,a);o.ok&&(this.enableEditContact(!1,t),i.props={...i.props,hash:o.json.newHash})}}c(l,"observedAttributes",["disabled"]),c(l,"properties",["props"]);export async function getTakeMessageDialog(n,t={}){const e=f();e.toggleAttribute("top",!0);const i=document.createElement("wc-take-message");for(i.toggleAttribute("caneditcontacts",n),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take a Message",confirm:"Submit"}),i.focus();;){if(!await e.waitClickedAction())return;if(!i.validate())continue;const a=await d.createTakeMessage(i.props);if(a.ok){e.close(),setTimeout(()=>a.notifySuccess("Message taken"),100);return}}}import m from"/static/skin/skin/x-field.min.css";import C from"/static/common/skin/cfm-heading.min.css";const b=[m,C];l.initComponent(String.raw`<div id="MAIN" class="d:f f-d:c g:--gap"><wc-select-client id="SELECT_CLIENT" newtab selectable sel1stsearch patternisnonelabel disable-if-disabled></wc-select-client><div cfm-heading>Contact</div><div id="CONTACTS" class="d:f f-d:c"><div class="js-main d:f a-i:c g:8px_16px f-g:1"><input id="SEL_ADD_CONTACT" x-field="widget" type="radio" name="select_contact" value="new" checked show-if-clientid><div class="d:f f-d:c g:8 f-g:1"><label for="SEL_ADD_CONTACT" class="f-w:500" show-if-clientid>New Contact</label><wc-contact id="NEW_CONTACT" class="f-g:1" show-if-addcontact disable-if-disabled></wc-contact><label for="ADD_CONTACT" class="d:f g:8 w:f-c m-y:4" show-if-clientid show-if-addcontact show-if-caneditcontacts><input id="ADD_CONTACT" type="checkbox" x-field="widget" disable-if-disabled><div title="If the client exists, it will be updated with this info">Add this contact to the client?</div></label></div></div><slot id="CONTACTS_SLOT" name="contacts"></slot></div><div class="d:f g:--gap f-w:w"><div class="d:f f-d:c g:--gap f-g:10" hide-if-disabled><div cfm-heading>Notify</div><select id="RECIPIENT" x-field="widget tonal stadium" class="o-y:v max-h:640" disable-if-disabled required></select></div><div class="d:f f-d:c g:--gap f-g:15"><label cfm-heading for="MESSAGE">Message</label><textarea id="MESSAGE" rows="4" x-field="widget tonal stadium" class="f-g:1" required disable-if-disabled></textarea><label for="CREATE_MEMO" class="d:f g:8 (w<640)m-y:8" hide-if-disabled show-if-clientid><input id="CREATE_MEMO" type="checkbox" x-field="widget" disable-if-disabled><div class="js-save-action" title="Also create a Client Memo that corresponds to this message">Also create a Client Memo?</div></label></div></div></div><template id="CONTACT_TEMPLATE"><div class="js-main d:f a-i:c j-c:e c-g:24 r-g:8 f-w:w"><div class="d:f a-i:c g:8px_16px f-g:10000"><input x-field="widget" type="radio" x-field="widget" name="select_contact" disable-if-disabled><label x-field="label" class="f-g:1" hide-if-disabled><wc-contact></wc-contact></label></div><div class="d:f a-i:c f-w:w (w>530)f-d:c g:16px_16px" hide-if-disabled show-if-caneditcontacts><wc-button type="tonal" color="primary" data-button="edit">EDIT</wc-button><wc-button type="text" color="bw" data-button="cancel" class="min-w:92 d:n">CANCEL</wc-button><wc-button type="solid" color="secondary" data-button="save" class="min-w:92 d:n">SAVE</wc-button></div></div></template> `,String.raw`styles`,b,"wc-take-message",[]);
Which means collect static fails:
Post-processing 'comms/wcapp/wc-take-message.min.js' failed! Traceback (most recent call last): File "/home/michael/project/src/manage.py", line 57, in <module> run() File "/home/michael/project/src/manage.py", line 49, in run execute_from_command_line(sys.argv) File "/home/michael/.venv/project/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line utility.execute() File "/home/michael/.venv/project/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/michael/.venv/project/lib/python3.11/site-packages/django/core/management/base.py", line 413, in run_from_argv self.execute(*args, **cmd_options) File "/home/michael/.venv/project/lib/python3.11/site-packages/django/core/management/base.py", line 459, in execute output = self.handle(*args, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/michael/project/src/core/app/base/management/commands/deploy.py", line 84, in handle call_command('collectstatic', '--noinput', '--clear', '--verbosity', '0') File "/home/michael/.venv/project/lib/python3.11/site-packages/django/core/management/__init__.py", line 194, in call_command return command.execute(*args, **defaults) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/core/management/base.py", line 459, in execute output = self.handle(*args, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 209, in handle collected = self.collect() ^^^^^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 154, in collect raise processed File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 375, in _post_process content = pattern.sub(converter, content) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 249, in converter hashed_url = self._url( ^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 182, in _url hashed_name = hashed_name_func(*args) ^^^^^^^^^^^^^^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 425, in _stored_name cache_name = self.clean_name(self.hashed_name(name)) ^^^^^^^^^^^^^^^^^^^^^^ File "/home/michael/.venv/project/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 143, in hashed_name raise ValueError( ValueError: The file 'skin/skin/x-field.min.c6fe58e9f403.css' could not be found with <base.storage.LcManifestStaticFilesStorage object at 0x7f645c578a10>.
Even though the file exists in the correct collect static spot:
:/var/www/example.com/public/static/skin/skin$ ls -la x-field.min.css -rw-r--r-- 1 michael www-data 6387 Apr 12 08:07 x-field.min.css
Change History (7)
follow-up: 2 comment:1 by , 7 months ago
comment:2 by , 7 months ago
Replying to Sarah Boyce:
Can you share what's in
base.storage.LcManifestStaticFilesStorage
here?
Sure:
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage class LcManifestStaticFilesStorage(ManifestStaticFilesStorage): support_js_module_import_aggregation = True
comment:3 by , 7 months ago
Summary: | JS module export regex does not handle certain minified code correctly → False positive in JS module aggregation export regex when an export declaration precedes an import declaration |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Bug |
Version: | 5.0 → dev |
Thank you for the report! Replicated on main.
This can occur also when the JS is not minified.
For anyone wanting to pick this up. If we make the following update:
diff --git a/tests/staticfiles_tests/project/documents/cached/module.js b/tests/staticfiles_tests/project/documents/cached/module.js index 7764e740d6..e9e61df56c 100644 --- a/tests/staticfiles_tests/project/documents/cached/module.js +++ b/tests/staticfiles_tests/project/documents/cached/module.js @@ -1,3 +1,4 @@ +export const moduleConst = "module"; // Static imports. import rootConst from "/static/absolute_root.js"; import testConst from "./module_test.js";
then tests for staticfiles_tests.test_storage.TestCollectionJSModuleImportAggregationManifestStorage
fail with the reported error.
comment:4 by , 6 weeks ago
Cc: | added |
---|---|
Owner: | changed from | to
Status: | new → assigned |
comment:5 by , 5 weeks ago
An observation: the extra line you add at the beginning of module.js
doesn't even have to be a proper export, if you add even //export
before the imports then it raises the same ValueError
comment:6 by , 3 weeks ago
Has patch: | set |
---|
comment:7 by , 12 days ago
Patch needs improvement: | set |
---|
Can you share what's in
base.storage.LcManifestStaticFilesStorage
here?