TwicPics/components

Problem to import esm version of @TwicPics/components/vue3 in esm project

awacode21 opened this issue · 7 comments

Hello,

i moved my project to be an esm only project. Before when importing @twicpics/components/vue3 in my cjs project everything works fine. But now when trying to import @twicpics/components/vue3 within my esm project i get an error within node_modules/@twicpics/components/vue3/module.js:1 saying "cannot use import statement outside a module".

There seems to be an issue within that @twicpics/components/vue3/module.js. Importing other ESM only packages is working totally fine.

I created a StackBlitz reproduction which is a stripped down version of my project setup. Just run npm run build & npm run preview on the terminal to see the error on production build:
https://stackblitz.com/edit/twicpic-in-vite-vue-esm-project

My project is using Vite + Vue3 + SSR

Error from terminal:

(node:33) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
/home/projects/twicpic-in-vite-vue-esm-project-vjscum/node_modules/@twicpics/components/vue3/module.js:1
import{openBlock as e,createElementBlock as t,createElementVNode as n,normalizeClass as o,normalizeStyle as i,createBlock as r,resolveDynamicComponent as s,mergeProps as a}from"vue";const c=e=>{if(!e)return;const[t,n,o]=e,i=t instanceof HTMLElement?t:document.createElement(t||"div");if(n)for(const[e,t]of Object.entries(n))i.setAttribute(e,String(t));if(o)if("string"==typeof o)i.innerHTML=o;else for(const e of Array.isArray(o)?o:[o]){const t=c(e);t&&i.appendChild(t)}return i},d=/px$/,l=e=>`twicpics-components ${e}`,u=(e,t=0)=>{let n;return()=>{n||(n=((e=0)=>new Promise((t=>e>0?setTimeout(t,e):t())))(t).then((()=>{n=void 0,e()})))}},p="undefined"!=typeof document,m=e=>{console.warn(l(e))},f=e=>{throw new Error(l(e))},b=(e,t)=>n=>{let o;return n&&n.replace(e,((e,t)=>o=t)),t?t(o):o},g=e=>new RegExp(`^\\s*(${Array.isArray(e)?e.join("|"):e})\\s*$`),v={domain:void 0,class:"twic"},w=/^https?:\/\/[^/]+$/,$=(e,t,n)=>({type:e,default:n,validator:t&&(e=>t.test(String(e)))}),y=e=>$(String,e),h=$([Number,String],/^\d+$/),_=y(),T=Object.assign(Object.assign({},_),{required:!0}),S=/\/?([^/?#.]+)(?:\.[^/?#]*)?(?:[?#].*)?$/,j=(e,t)=>{if(!e){const n=S.exec(t);e=n&&n[1]||"image"}return e},O=(e,t,n,o)=>{const i={};return e&&(i[`data-${v.class}-bot`]=e),t&&(i[`data-${v.class}-focus`]=t),n&&(i[`data-${v.class}-src`]=n),void 0!==o&&(i[`data-${v.class}-step`]=String(o)),i},z=(e,t,n,o,i)=>{const r={};return e&&(r.objectFit=e),t&&(r.objectPosition=t),o&&(r.transitionDuration=o),n&&(r.transitionDelay=n),i&&(r.transitionTimingFunction=i),r},x=e=>{const t=["twic-w"];return e.includes("none")||(e.includes("zoom")&&t.push("twic-tz"),e.includes("fade")&&t.push("twic-tf")),t.join(" ")},D=(e,t,n,o,i,r,s,a)=>{const c={};return a({focus:e,mode:t,placeholder:n,ratio:i,transitions:s,src:r}),t&&(c.backgroundSize=t),o&&(c.backgroundPosition=o),c.paddingTop=void 0===i?"":100*i+"%",c},N=g(["contain","cover"]),A=g(["maincolor","meancolor","none","preview"]),M=g("(\\d+(?:\\.\\d+)?)(?:\\s*\\/\\s*(\\d+(?:\\.\\d+)?))?"),C=/^(image:)?\/?/,I=e=>!isNaN(e)&&e>0,P=b(g(".+?")),k=P,E=P,R=P,F=b(N),V=b(A,(e=>e?"none"===e?void 0:e:"preview")),W=P,B=e=>{let t;if("number"==typeof e)t=e;else if(e){const n=M.exec(e);if(n){const[,,e,o]=n;t=(o?Number(o):1)/Number(e)}else t=1}return I(t)?t:void 0},H=e=>{if("number"!=typeof e){const t=P(e);e=t&&Number(t)}return I(e)?e:void 0},L=e=>(e=P(e))?e.replace(C,"image:"):void console.error(l("src is mandatory")),q=e=>{const t={true:"fade",false:"none",fade:"fade",zoom:"zoom",none:"none"};"boolean"!=typeof e&&(e=P(e)||!0);let n=String(e).split("+").map((e=>t[e]||"fade"));return n.includes("none")&&(n=["none"]),n},G=P,J=P,K=P,Q=` TPCWBG ${Math.random()} ${Date.now()} `,U=p&&"undefined"!=typeof ResizeObserver&&new ResizeObserver((e=>{for(const{target:t}of e)t[Q]()}));p&&!U&&m("ResizeObserver not found");const X=(e,t)=>{const n=t.map((e=>"function"==typeof e?{f:e}:{s:`p_${e}`}));return function(){return e(...n.map((({f:e,s:t})=>e?e(this):this[t])))}},Y={},Z={};for(const[e,t,n]of[["alt",_,k],["bot",_,E],["focus",_,R],["mode",y(N),F],["placeholder",y(A),V],["position",_,W],["ratio",y(M),B],["src",T,L],["step",h,H],["transition",$([Boolean,String],null,!0),q],["transitionDelay",_,G],["transitionDuration",_,J],["transitionTimingFunction",_,K]])Y[`p_${e}`]=function(){return n(this[e])},Z[e]=t;for(const[e,t,n]of[["_alt",j,["alt","src"]],["_dataAttributes",O,["bot","focus","src","step"]],["_style",z,["mode","position","transitionDelay","transitionDuration","transitionTimingFunction"]],["_wrapperClass",x,["transition"]],["_wrapperStyle",D,["focus","mode","placeholder","position","ratio","src","transition",e=>e._p.setData]]])Y[e]=X(t,n);var ee={props:Z,computed:Y,beforeCreate(){this._p=(e=>{let t,n,o,i;return v.domain||m("domain has not been configured "),{delete:()=>{t&&(U&&U.unobserve(t),delete t[Q])},setData:e=>{o=e,i&&i()},setWrapper:e=>{Object.defineProperty(t=e,Q,{configurable:!0,value:i=u((()=>{if(t&&v.domain&&o){const i=((e,{focus:t,mode:n,placeholder:o,ratio:i,transitions:r=[],src:s})=>{if(!o||!s||r.includes("zoom"))return"";const a=getComputedStyle(e),c=null!=i?i:(l=a.fontSize,Number(l.replace(d,"")));var l;let u=1e3,p=1e3;c<1?u*=c:p/=c,u=Math.max(1,Math.round(u)),p=Math.max(1,Math.round(p));const m=n||F(a.backgroundSize)||"cover";return`${"cover"===m&&t?`focus=${t}/`:""}${m}=${p}x${u}/output=${o}/${s}`})(t,o);if(i&&i!==n){n=i;const t=`url(${JSON.stringify(`${v.domain}/v1/${i}`)})`;e.style.backgroundImage=t}}}))}),U&&U.observe(t)}}})()},mounted(){this._p.setWrapper(this.$refs.w)},unmounted(){this._p.delete()},render:function(c,d,l,u,p,m){return e(),t("div",null,[n("div",{ref:"w",class:o(c._wrapperClass),style:i(c._wrapperStyle)},[(e(),r(s(c._is),a({alt:c._alt,style:c._style},{...c._dataAttributes}),null,16,["alt","style"]))],6)])},__file:"src/vue/base.vue"};const{computed:te}=ee;var ne=(e,t,n)=>{e.component(t,Object.assign(Object.assign({},ee),{name:t,computed:Object.assign({_is:()=>n},te)}))};const oe=(e,t)=>{(e=>{e||f("install options not provided");const t=v&&v.domain,{domain:n,class:o}=e;if(n&&w.test(n)||f(`install domain "${n}" is invalid`),v.domain=n,v.class=o||"twic",p){if(t)return void m("install function called multiple times");const o=[`${n}/?v1`];Object.entries(e).forEach((([e,t])=>{if(null!=t){let n=e;"maxDPR"===e&&(n="max-dpr"),"domain"!==e&&o.push(`${n}=${t}`)}})),c([document.head,0,[["link",{rel:"preconnect",href:n}],["script",{async:"",defer:"",src:o.join("&")}],["style",0,`.twic-w>.${v.class}-done{opacity:1 !important;transform: scale(1) !important;}`]]])}})(t),t.TwicImg&&t.TwicImg===t.TwicVideo&&f("TwicImg and TwicVideo components must have different names"),ne(e,t.TwicImg||"TwicImg","img"),ne(e,t.TwicVideo||"TwicVideo","video")};export{oe as default};
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (https://twicpic-in-vite-vue-esm-project-vjscum.w.staticblitz.com/blitz.49c6d2ee58ce7c1528881cc6d46ebf056b3b42bf.js:6:341307)
    at wrapSafe (https://twicpic-in-vite-vue-esm-project-vjscum.w.staticblitz.com/blitz.49c6d2ee58ce7c1528881cc6d46ebf056b3b42bf.js:6:218269)
    at Module._compile (https://twicpic-in-vite-vue-esm-project-vjscum.w.staticblitz.com/blitz.49c6d2ee58ce7c1528881cc6d46ebf056b3b42bf.js:6:218637)
    at Object.Module._extensions..js (https://twicpic-in-vite-vue-esm-project-vjscum.w.staticblitz.com/blitz.49c6d2ee58ce7c1528881cc6d46ebf056b3b42bf.js:6:219665)
    at Module.load (https://twicpic-in-vite-vue-esm-project-vjscum.w.staticblitz.com/blitz.49c6d2ee58ce7c1528881cc6d46ebf056b3b42bf.js:6:217691)
    at Function.Module._load (https://twicpic-in-vite-vue-esm-project-vjscum.w.staticblitz.com/blitz.49c6d2ee58ce7c1528881cc6d46ebf056b3b42bf.js:6:215262)
 

Hello @awacode21 . Thanks for the reproduction example.

It is fixed in https://stackblitz.com/edit/twicpic-in-vite-vue-esm-project-ytfjjb

On line #55 of /server.js, the index option of serveStatic is set to false. This makes it so targeting / with the browser would have the server not send index.html but going further down its express middlewares where it imports the unbundled code and triggers the error.

By setting the index option to "index.html", everything works as expected. However, since unknown paths like https://twicpic-in-vite-vue-esm-project-ytfjjb--3000.local.webcontainer.io/something would still try and import the unbundled file, I added a shortcut return { app, vite }; at line #58 so that it creates a 404 instead and behaves as a pure static server.

So the bundle was created correctly, it is the server code that created the issue.

Hello Julian,
thank you for investing the time and checking for me. I can't express how much that means to me.
Unfortunately, it's not the solution. These adjustments to the code mean that it doesn't render server-side anymore. The index.html is now no longer processed server-side. What we are seeing is client-side success. However, on the console we see the hydration mismatch and if I look at the page source delivered by the server, that is the Index.html before it is processed by the server, not after.
The intended background of the serveStatic function is to move all static files to Dist, except for the Index.html ... because it is supposed to be processed on the server side. The index need to run through the next app.use where the server side rendering takes place. Also all that unknown routes must be processed by the server, because only the vue app knows which routes are known and which ones not, the vue app takes care about 404.

With the changes you made in the code, you kick out the SSR completely, because it will never run. For this reason, the error no longer occurs because the import is never carried out on the server side. But not to have server-side rendering and change to a pure static server just to hide an error is not option for my project. Server was configured the right way.

Please reopen the issue., it's still an issue. @jaubourg @mbgspcii

Best regards, Annick

Bildschirmfoto 2022-04-24 um 21 40 08

Bildschirmfoto 2022-04-24 um 21 40 23

i think it's still a bug with @TwicPics/components/vue3/module.js

To compare: this is the exact same project, also with the exact same Server-Side-Rendering Setup. The only difference is that it is cjs, no error with the twicpic import here: https://stackblitz.com/edit/twicpic-in-vite-vue-ssr-project-without-esm

But when the project, same setup is an ESM project, the error occures, within the module.js of twicpic/components/vue3.. inside, not outside where i call it.

To sum up: we figured out that the issue is related to the fact that both exports, the cjs export and the esm export end with .js
That confuses the loader, as there is no differentiation in file, it expects it to be cjs and loads it as it would be cjs. That is why the error occurs. So just pointing for imports to module.js was not working.

It needs to be named module.mjs to be recognized as esm module.

Julian is currently working on the fix.

Fixed with release von Version 0.6.4