Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.7.x] Build MJS and CJS versions of the plugin #189

Merged
merged 1 commit into from May 9, 2023

Conversation

timacdonald
Copy link
Member

@timacdonald timacdonald commented Dec 20, 2022

tl;dr; This PR brings support for projects using "type": "modules" to the Laravel plugin.

Background

In there beginning, of this story at least, there were "CJS" or Common JS modules. CJS was the module system that Node created. It uses require() and modules.export.

Life was good in Node-land and the developers rejoiced in the streets.

Browsers did not support this standard.

ECMAScript then standardised ES Modules "MJS". This module system uses import X from './foo' and export { X } type syntax.

Unfortunately for package maintainers there was now a need to compile both CJS and MJS builds. Some build tools or systems required CJS, while others required MJS.

These were the darkest of days.

After a good while, the ecosystem caught up. MJS and CJS was available for most relevant packages. The developers, once again, rejoiced in the streets - although the package maintainers lost sleep trying to work out how to even build two outputs and why this noise even exists. Here is, the one and only, "Wes Bos" with more...

Screen Shot 2023-05-03 at 10 58 54 am

Anyone who has done this can feel the pain emanating from this tweet.

Slowly though, the tide has shifted. Many mainstream packages are now dropping support for CJS and it seems this is the direction the ecosystem is heading. Again, Wes Bos with more...

Screen Shot 2023-05-03 at 11 00 59 am

MJS is now supported by browsers, which is how Vite works. I don't believe browsers natively support MJS at all.

I don't think Node yet officially supports MJS. I believe there is experimental support for it.

**The facts may vary, but this is the general gist of things.

Why

With a fresh install of Laravel, some major Vite plugins no longer work out of the box. The Svelte plugin, for example, no longer supports projects without "type": "module". "type": "module" tells build tools, such as Vite, that you want to use ESM.

See: #187

With Laravel's switch to Vite, all project level dependencies, that is dependencies that you use in your application code, already need to be MJS. Vite only works with projects using MJS. However, Vite plugins referenced in the vite.config.js file may be CJS or MJS.

This PR introduces an MJS version of the plugin so that we can make the package.json file use "type": "module" by default.

This PR is only additive. It does not remove the CJS build. This means projects without "type": "module" will continue to build, as we continue to ship CJS.

See:

@timacdonald
Copy link
Member Author

@lrfahmi @CodeKJ @fpolli would appreciate it if you could take a look at this PR and take it for a test.

@fpolli
Copy link

fpolli commented Dec 20, 2022

Thank you for reopening this and jumping on it so quickly. I will give it a try.

@CodeKJ
Copy link

CodeKJ commented Dec 20, 2022

@lrfahmi @CodeKJ @fpolli would appreciate it if you could take a look at this PR and take it for a test.

Doesn't work for me. Here are my configs and result. Let me know if I something is missing on my side - I haven't really tested packages with specific commits before, fresh npm install was successful tho.

package.json

{
    "type": "module",
    "private": true,
    "scripts": {
        "dev": "vite",
        "build": "vite build",
        "watch": "vite build --watch"
    },
    "devDependencies": {
        "@sveltejs/vite-plugin-svelte": "^2.0.2",
        "autoprefixer": "^10.4.4",
        "axios": "^0.27",
        "laravel-vite-plugin": "github:timacdonald/vite-plugin#4f0383ea8a310226f1b859049964bfe94d07f307",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "tailwindcss": "^3.0.23",
        "vite": "^4.0.0"
    },
    "dependencies": {
        "@inertiajs/inertia": "^0.11.1",
        "@inertiajs/inertia-svelte": "^0.8.0",
        "@inertiajs/progress": "^0.2.7",
        "svelte": "^3.46.6",
        "svelte-loader": "^3.1.2"
    }
}

vite.config.js

import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/js/app.js',
        ]),
        svelte({
            prebundleSvelteLibraries: true,
        }),
    ],
    optimizeDeps: {
        include: [
            "@inertiajs/inertia",
            "@inertiajs/inertia-svelte",
        ]
    }
});

Result after npm run dev

Output
> dev
> vite

✘ [ERROR] [plugin externalize-deps] Failed to resolve entry for package "laravel-vite-plugin". The package may have incorrect main/module/exports specified in its package.json.

  node_modules/esbuild/lib/main.js:1355:27:
    1355 │         let result = await callback({
         ╵                            ^

  at packageEntryFailure (file:///var/www/html/node_modules/vite/dist/node/chunks/dep-6305614c.js:22973:11)
  at resolvePackageEntry (file:///var/www/html/node_modules/vite/dist/node/chunks/dep-6305614c.js:22970:5)
  at tryNodeResolve (file:///var/www/html/node_modules/vite/dist/node/chunks/dep-6305614c.js:22708:20)
  at file:///var/www/html/node_modules/vite/dist/node/chunks/dep-6305614c.js:63066:40
  at requestCallbacks.on-resolve (/var/www/html/node_modules/esbuild/lib/main.js:1355:28)
  at handleRequest (/var/www/html/node_modules/esbuild/lib/main.js:723:19)
  at handleIncomingPacket (/var/www/html/node_modules/esbuild/lib/main.js:745:7)
  at Socket.readFromStdout (/var/www/html/node_modules/esbuild/lib/main.js:673:7)
  at Socket.emit (node:events:513:28)
  at addChunk (node:internal/streams/readable:315:12)

This error came from the "onResolve" callback registered here:

  node_modules/esbuild/lib/main.js:1279:20:
    1279 │       let promise = setup({
         ╵                     ^

  at setup (file:///var/www/html/node_modules/vite/dist/node/chunks/dep-6305614c.js:63055:27)
  at handlePlugins (/var/www/html/node_modules/esbuild/lib/main.js:1279:21)
  at buildOrServeImpl (/var/www/html/node_modules/esbuild/lib/main.js:968:5)
  at Object.buildOrServe (/var/www/html/node_modules/esbuild/lib/main.js:776:5)
  at /var/www/html/node_modules/esbuild/lib/main.js:2115:17
  at new Promise (<anonymous>)
  at Object.build (/var/www/html/node_modules/esbuild/lib/main.js:2114:14)
  at build (/var/www/html/node_modules/esbuild/lib/main.js:1961:51)
  at bundleConfigFile (file:///var/www/html/node_modules/vite/dist/node/chunks/dep-6305614c.js:63019:26)

The plugin "externalize-deps" was triggered by this import

  vite.config.js:3:20:
    3 │ import laravel from 'laravel-vite-plugin';
      ╵                     ~~~~~~~~~~~~~~~~~~~~~

failed to load config from /var/www/html/vite.config.js
error when starting dev server:
Error: Build failed with 1 error:
node_modules/esbuild/lib/main.js:1355:27: ERROR: [plugin: externalize-deps] Failed to resolve entry for package "laravel-vite-plugin". The package may have incorrect main/module/exports specified in its package.json.
  at failureErrorWithLog (/var/www/html/node_modules/esbuild/lib/main.js:1594:15)
  at /var/www/html/node_modules/esbuild/lib/main.js:1050:28
  at runOnEndCallbacks (/var/www/html/node_modules/esbuild/lib/main.js:1466:61)
  at buildResponseToResult (/var/www/html/node_modules/esbuild/lib/main.js:1048:7)
  at /var/www/html/node_modules/esbuild/lib/main.js:1160:14
  at responseCallbacks.<computed> (/var/www/html/node_modules/esbuild/lib/main.js:697:9)
  at handleIncomingPacket (/var/www/html/node_modules/esbuild/lib/main.js:752:9)
  at Socket.readFromStdout (/var/www/html/node_modules/esbuild/lib/main.js:673:7)
  at Socket.emit (node:events:513:28)
  at addChunk (node:internal/streams/readable:315:12)

@fpolli
Copy link

fpolli commented Dec 21, 2022

Hi, the one commit for this modifies tsconfig files. Those files are not in my plugin folder. I tried npm update and npm install and still those files were not copied over. I see them in the git code list. I'm confused. Am I doing something wrong?

@timacdonald
Copy link
Member Author

timacdonald commented Dec 21, 2022

Hey folks, sorry about that. I should have provided some steps for you to properly test this.

What you will need to do is clone my repo / branch, build the plugin, and then link the plugin in your project.

To setup the plugin, do the following somewhere outside of your project...

git clone https://github.com/timacdonald/vite-plugin.git laravel-vite-plugin
cd laravel-vite-plugin
git checkout module-support
npm install
npm run build
npm link

Then in your projects directory, run npm link laravel-vite-plugin. This will create a symlink in your projects node_modules that points to your local version of the laravel-vite-plugin.

Once you have done that you will hopefully be able to run npm run build in your project.

@CodeKJ I was able to copy your package.json and vite.config.js and my build worked as expected with the changes in this PR, but I would still love for you to confirm the fix.

@fpolli
Copy link

fpolli commented Dec 22, 2022

Thank you for that info. I went through that process and everything went fine until I tried to start the vite dev server. I ran npm run dev -- --host and received this error message:

error when starting dev server:
Error: dotenv-expand failed to expand env vars. Maybe you need to escape $?
at loadEnv (/Users/name/Sites/seeds/laravel-vite-plugin/node_modules/vite/dist/node-cjs/publicUtils.cjs:4270:19)
at config (/Users/name/Sites/seeds/laravel-vite-plugin/dist/index.cjs:63:43)
at runConfigHook (file:///Users/name/Sites/seeds/node_modules/vite/dist/node/chunks/dep-5605cfa4.js:63173:31)
at async resolveConfig (file:///Users/name/Sites/seeds/node_modules/vite/dist/node/chunks/dep-5605cfa4.js:62676:14)
at async createServer (file:///Users/name/Sites/seeds/node_modules/vite/dist/node/chunks/dep-5605cfa4.js:61943:20)
at async CAC. (file:///Users/name/Sites/seeds/node_modules/vite/dist/node/cli.js:707:24)

I tried a google search and did not find anything on point.

Thanks

@timacdonald
Copy link
Member Author

@fpolli It seems you might have a dollar sign in your .env file you are loading via loadEnv that should be escaped, but is not currently escaped.

I can only replicate your issue if I purposefully introduce an un-escaped dollar sign, for example when I add the following to my .env and load that file via loadEnv I get the error you are reporting.

CORS_ALLOWED_ORIGINS=/${SERVER_HOST}(:[0-9]+)?$/

To fix this, you can escape the last dollar sign:

- CORS_ALLOWED_ORIGINS=/${SERVER_HOST}(:[0-9]+)?$/
+ CORS_ALLOWED_ORIGINS=/${SERVER_HOST}(:[0-9]+)?\$/

Related:

@fpolli
Copy link

fpolli commented Dec 23, 2022

Wow, there was a dollar sign in my email password.

Thanks!

@timacdonald
Copy link
Member Author

@fpolli were you able to test this after fixing that issue in your .env?

@fpolli
Copy link

fpolli commented Dec 28, 2022

Hi Tim,
Yes, I was and it serves a page, but I just noticed that Vite says version 3.2.5 and I thought this setup was for 4.0, so I'm not sure where I stand. It reports Laravel 9.44 and plugin 0.7.2.

@innocenzi
Copy link
Contributor

Hey @timacdonald, I suggest using some higher-level tool like unbuild so your build scripts can be greatly simplified. A multi-output config (ESM + CJS + types) would look like the following in a build.config.ts file:

import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
  entries: [
    './src/index',
    './src/inertia-helpers/index',
  ],
  clean: true,
  declaration: true,
  externals: [
    // ?
  ],
  rollup: {
    emitCJS: true,
  },
})

@ankurk91
Copy link

ankurk91 commented Jan 29, 2023

@timacdonald
I have the same issue. :(

Can we make the "type": "module", in Laravel 10 skeleton?

You can read about Pure ESM Modules here.
https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

This will make Laravel future proof.
+

Tip:
You can tag a beta version of plugin like

npm publish --tag beta
Then
users can install and test it like

npm install package_name@beta

@timacdonald
Copy link
Member Author

timacdonald commented Jan 30, 2023

I agree that we should probably make this the default in Laravel skeleton (it's a todo in the PR description), but I need more testing on this from the community to ensure we don't break things.

If you could pull this down, test it, and report if it worked as expected, that would be amazing.

@ereveniaud
Copy link

As a workaround, you could use this :

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
-       laravel({
+       laravel.default({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
    ],
});

package.json Show resolved Hide resolved
package.json Show resolved Hide resolved
@Magnesium38
Copy link

Hey folks, sorry about that. I should have provided some steps for you to properly test this.

What you will need to do is clone my repo / branch, build the plugin, and then link the plugin in your project.

To setup the plugin, do the following somewhere outside of your project...

git clone git clone https://github.com/timacdonald/vite-plugin.git laravel-vite-plugin
cd laravel-vite-plugin
git checkout module-support
npm install
npm run build
npm link

Then in your projects directory, run npm link laravel-vite-plugin. This will create a symlink in your projects node_modules that points to your local version of the laravel-vite-plugin.

Once you have done that you will hopefully be able to run npm run build in your project.

@CodeKJ I was able to copy your package.json and vite.config.js and my build worked as expected with the changes in this PR, but I would still love for you to confirm the fix.

Just wanted to chime in here and say I'm running into this underlying issue as well and stumbled upon this PR and did try these steps and using the linked branch instead does seem to get things nearly working. One caveat to that working is that the TS types aren't being picked up by vscode.

I was able to fix it by restoring the types key that was deleted in addition to leaving the new exports key. I'm not nearly enough of an expert in this to say if leaving it would break anything, but it seems that it's okay to have both.

Would be happy to test out any other changes to this PR.

@jessarcher jessarcher marked this pull request as ready for review May 2, 2023 23:45
@jessarcher
Copy link
Member

I just gave this a try, and it works great!

I tested an existing app where "type": "module" is not set (and cannot be set without this PR), and both dev and build modes worked great with no changes so I don't see this breaking any existing apps.

I was then able to set "type": "module" (which previously was not possible but seems like the way things are headed), and it also worked once I either renamed my Tailwind and PostCSS configs to .cjs or changed them to use import/export.

@timacdonald timacdonald marked this pull request as draft May 3, 2023 02:27
@timacdonald timacdonald marked this pull request as ready for review May 3, 2023 03:15
package.json Show resolved Hide resolved
@driesvints driesvints merged commit d446d2d into laravel:main May 9, 2023
3 checks passed
@timacdonald timacdonald deleted the module-support branch May 9, 2023 23:05
@RobertBoes
Copy link

Seems like this, along with the changes in Breeze, does break things. To reproduce:

composer create-project laravel/laravel=v10.1.1 demo --prefer-dist

cd demo

composer require laravel/breeze

php artisan breeze:install vue

This results in the following error:

vite v4.3.5 building for production...
transforming (18) node_modules/vue/dist/vue.runtime.esm-bundler.js(node:29166) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /[path-to-project]/demo): [SyntaxError] Unexpected token 'export'
/[path-to-project]/demo/postcss.config.js:1
export default {
^^^^^^

SyntaxError: Unexpected token 'export'
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1187:20)
    at Module._compile (node:internal/modules/cjs/loader:1231:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1321:10)
    at Module.load (node:internal/modules/cjs/loader:1125:32)
    at Module._load (node:internal/modules/cjs/loader:965:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:165:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:192:25)]

Node.js v20.1.0

@ankurk91
Copy link

rename the file postcss.config.js to postcss.config.cjs, i should work

@timacdonald
Copy link
Member Author

@RobertBoes laravel/breeze is only supported for new projects, which assumes you are running the latest version of Laravel.

@dammy001
Copy link

@RobertBoes laravel/breeze is only supported for new projects, which assumes you are running the latest version of Laravel.

Exactly because it's now ESM first. @RobertBoes rename your .js files to .cjs and make use of module.exports in that file

@RobertBoes
Copy link

@timacdonald This was a new project. I created a project before the latest release, added Breeze and then I got that error. It was right in between releases, yes, but still caused the error.

And yes, I know how to fix it, I'm not asking how I could fix this issue, but it seems to me to introduce a breaking change.

erikgreasy added a commit to BRACKETS-by-TRIAD/admin-ui that referenced this pull request Oct 26, 2023
Laravel added default "type": "module" to their package.json in PR: laravel/vite-plugin#189. This breaks compilation with laravel-mix and therefore we need to remove this line from package.json in the installation process. The ability to compile with Vite shouldn't be affected by this, however some specific modules (like svelte) can be affected by this, as mentioned in the Laravel's PR. We think that the potential problem with specific libraries should be resolved by developer that uses them.
@archoda
Copy link

archoda commented Mar 28, 2024

What's the actual fix here?

@timacdonald
Copy link
Member Author

@archoda, what issue are you facing exactly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet