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

How to develop a webpack package locally ? #1129

Open
Cartman34 opened this issue Jun 23, 2022 · 4 comments
Open

How to develop a webpack package locally ? #1129

Cartman34 opened this issue Jun 23, 2022 · 4 comments

Comments

@Cartman34
Copy link

Cartman34 commented Jun 23, 2022

Hi,

I am developing a Symfony bundle using classic Sf features (views, controllers, entities,...;) but with also JS stimulus controllers and SCSS.
So, the project stack is Npm + Webpack Encore + Stimulus + PHP + Symfony 6.1.

By installing the local composer package, Flex should consider my bundle as an embedded node module, but Flex does nothing, I linked it manually, this works but not perfectly and I would do it the legit way.

To develop the bundle, I created a package.json in the assets folder in a separate project. The package is added to the project by its local path on my file system using "file:", then I run npm run watch, this is working properly, sometimes I am getting errors with missing core-js.
But by developing locally, I would changes to be detected by webpack to compile the new changes. Using "file:", yarn/node seems to create a copy of my sources, so it won't listen the sources for changes.

I also tried using link: but webpack is failing to compile.

So the whole thing is a bunch of wonky repairs and I did not find a good tutorial to explain how to do that with Webpack Encore + Sf 6.1.

How to develop a webpack package locally ?
How is this recommended ?
Considering, I can not run a symfony or docker server, everything is on a local VM and PhpStorm is deploying automatically on it..

NB: I am looking for information, I tried stackoverflow with no success.

@weaverryan
Copy link
Member

Yea, this is not a super easy process. You should (and it sounds like you already are) follow the examples from the symfony/ux repository - e.g. https://github.com/symfony/ux/tree/2.x/src/Autocomplete

What I usually do (and there is almost definitely some room for improvement) is this:

A) I have a WIP version of my bundle locally
B) I create a brand new Symfony project that I will use for testing the bundle.
C) I install the bundle using a "path" repository - https://getcomposer.org/doc/05-repositories.md#path - just a simple way of getting the bundle installed "properly" into your app... but it really just points at your local directory.
D) I then usually (to easy dev) delete the vendor/ directory of the bundle and replace it with a symlink. e.g. rm -rf vendor/symfony/ux-autocomplete then replace it with a symlink to where the bundle actually lives on my system. Then, php changes to the bundle will be used instantly.

Now, about the JS part, which is what you're really asking about.

By installing the local composer package, Flex should consider my bundle as an embedded node module, but Flex does nothing, I linked it manually, this works but not perfectly and I would do it the legit way.

Make sure you have the symfony-ux keyword - https://github.com/symfony/ux/blob/990fb8e717486bf775a7cc6683725f8d81b49968/src/Autocomplete/composer.json#L6 - that is actually the trigger (and that needs to be documented).

If your bundle is setup correctly (and it sounds like it is), you should now have the file: part in your package.json pointing to the bundle in vendor/. And so, in theory, everything should work (assuming the js "package" in your bundle has been packaged up into a dist directory - we use rollup for this).

Let me know what issues you hit. The process is cumbersome, and I'd welcome any automation or documentation for this. Additionally, I often will disable the Stimulus controller I'm working on in assets/controllers.json, but instead register it manually in assets/bootstrap.js... but point directly to the vendor version of the file (e.g. import '../vendor/symfony/..../dist/controller). The reason is that the path will now look like it is NOT in node_modules/, and so yarn watch will rebuild when it sees changes and you can, in theory, even point this at your source typescript files and those can be parsed (whereas normally if you point Webpack at .ts files in node_modules, it will not parse them as it expects node_modules stuff to already be in normal JS).

Cheers!

@Cartman34
Copy link
Author

Cartman34 commented Jun 24, 2022

Hi, a great thank you ! You saved my day by fixing the half of the issues !

About A/B/C, I am doing this way.
About D, My bundle has no vendor as it does not run by itself, I never ran composer in it, I edit it's composer.json manually, is it good ?

About symfony-ux keyword, this was the missing part. It seems there is a lack of documentation about this, maybe it should be here => https://symfony.com/doc/current/frontend/ux.html
And many (All ?) UX projects are using the former folder structure (Resources/assets/src/).
It's now handling package.json and controllers.json
I think a complete & solid example should go with documentation (Autocomplete ?).

In bundle, my assets are in assets/ folder, as required by documentation, my bundle has no compiled ressources as it has to consider the style and customization of main projet, so the main project compiled it, it could contain SCSS files, JS services, JS stimulus controllers, other JS classes...

I will try your tips, I tried to override watch options to change ignored properties in webpack.config.js with no real success.

	.configureWatchOptions(function (watchOptions) {
		watchOptions.ignored = /node_modules([\\]+|\/)+(?!sowapps)/;
	})

It's inspired from something I found on the internet

But for this part, I am still stuck with core-js issue. I will answer you in the mentioned issue.

EDIT:
I tried to register controller using

import MyController from '../vendor/author/package/assets/controllers/input/my_controller.js';
app.register('author--package--input-my', MyController);

But I am still having the core-js issue.

@anatholius
Copy link

anatholius commented Sep 23, 2022

Hi @Cartman34, @weaverryan

I am also trying to figure out how to create a bundle (and also libraries), with nice DX, containing frontend resources according to Symfony UX solutions.

I was able to create a setup for local development to use existing solutions completely without hacking core files.
So I wanted to share this adventure and verify it doesn't break any rules (or does it only work for me?)

Here's what I did:

  • I created a symfony package based on documentation and existing ux repositories.

    OS Ubuntu 22.04, Symfony 6.1, node 18.5, npm 8.19.2, yarn 3.2.3, reactjs 18.2

    In fact, with many changes to the Symfony ecosystem over the past year, it's hard to put together all needed information.

  • I installed the package according to Ryan's solution C)
  • ''' Important is the "keywords": ["symfony-ux"] part in bundle's composer.json
  • I have assets in the /assets folder, but I noticed that it does not matter whether it is according to the old or new convention - it just works
  • JS part
    • in app:

      • The thing I do is set up package.json in the application to use symlinks for my package (for development time)
        • by hands in /package.json
          "resolutions": {
              "@vendor_name/my-shiny-new-bundle": "portal:$HOME/path/to/bundle/assets"
          }
        • or via command:
          yarn link $HOME/path/to/bundle/assets
    • in bundle:

      • First, I did some alpine combinations with symlinks in the opposite direction,

        "devDependencies": {
            "@hotwired/stimulus": "portal:../up/stairs/to/the/{app}/node_modules/@hotwired/stimulus",
            "core-js": "portal:../up/stairs/to/the/{app}/node_modules/core-js",
            "react": "portal:../up/stairs/to/the/{app}/node_modules/react",
            "react-dom": "portal:../up/stairs/to/the/{app}/node_modules/react-dom",
            ...
        }
      • but at the end it turned out, that devDependencies are not needed at all

      • flex installs the package and adds to package.json something like:

        "@vendor_name/my-shiny-new-bundle": "file:vendor/vendor_name/my-shiny-new-bundle/assets"

        "Don't forget to run npm install --force or yarn install --force to refresh your JavaScript dependencies!"

      of course, just yarn

      I'm using yarn ^3 so there is no flag --force, instead you can use --check-cache, the word install is not needed

      All this results in:

      • composer installs symlinks Symlinking from ...
      • yarn installs symlinks but:
        ➤ YN0072: │ The application uses portals and that's why --preserve-symlinks Node option is required for launching it

      So, last piece of cake:

      • Go into webpack.config.js:
        const webpackConfig = Encore
            // ...
            // some magic
            // ...
            .getWebpackConfig()
        webpackConfig.resolve.symlinks = true
        
        module.exports = webpackConfig

As tested, it works great for both dev-server and watch
app and bundle at the same time and even in the same IDE


There is no core-js or even react issues, but of course it depends on setup.


Hope it helps someone

@carsonbot
Copy link

Thank you for this issue.
There has not been a lot of activity here for a while. Has this been resolved?

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

No branches or pull requests

4 participants