Code Monkey home page Code Monkey logo

Comments (45)

dkarlovi avatar dkarlovi commented on May 21, 2024 14

@weaverryan basically, if I install a bunch of bundles, some of them might need their assets to be installed. If used, I'd expect Encore to basically just work with them, without me reading Webpack docs and figuring out what goes where (for 3rd party bundles, mind you).

So, use case is:

  1. I install the bundle
  2. Encore figures out that it's there and how to expose its assets to Webpack
  3. Webpack does what ever it needs to
  4. Stuff works for me (the developer) and my end users without me figuring out Webpack

from webpack-encore.

fvsch avatar fvsch commented on May 21, 2024 7

Apologies for the long comment. I'd like to highlight a common-ish use-case with "assets stored in bundles", the current solution as far as I can tell, and how it might be improved a bit.

With Assetic we tend to use:

{% stylesheets
  '@SomeBundle/Resources/public/css/something.css'
  '@OtherBundle/Resources/public/css/other-thing.css'
%}
  <link rel="stylesheet" src="{{ asset_url }}">
{% endstylesheets %}

(On different platforms there are similar tools, using config rather than template tags most of the time, but the rationale is that you tend to give it the path to some files to concatenate and perhaps minify.)

Looking at the Encore docs, if you have a specific script from a bundle as a dependency, you could have:

// my/entry/point.js
require('../../vendor/some-vendor/some-bundle/src/Resources/public/css/something.css');
require('../../vendor/other-vendor/other-bundle/Resources/public/css/other-thing.css');

And if your main entry point uses the name 'app', you will get a corresponding 'app.css', yay for that! My understanding is that this is "just" normal webpack behavior, with some css-loader (to enable requiring CSS files) and the Extract Text plugin, used by default by Encore.

The one issue with this approach is that referencing files from bundles can be a pain, what with the sea of .. and all, especially if you want to require a file as a dependency from a script deeper in your folder structure.

One way to make it better would be to have some webpack aliases:

  1. either a simple '@vendor/' (and then you're on your own for looking up the exact paths);
  2. or a @/ alias that matches the root of the project (like some JS frameworks do for the src folder, except src in those frameworks does not match the src folder in Symfony 3, let alone Symfony 4, so root is better);
  3. or even one alias per installed bundle, matching what both Assetic and the Twig component do.

The first two have some complexity (what if your webpack.config.js is not at the root of the project, or your Symfony structure is atypical?) so instead of doing it magically it's probably better to offer an helper to declare aliases explicitly.

The third option would require some PHP tool to publish a map of sorts.

Encore itself could have a method for defining webpack

Encore
  .addAlias({'@': './'})
  .addAlias(require('./var/whatever/bundle-map.json'))

Or that can be done manually I think:

const config = Encore
  /* ... */
  .getWebpackConfig();

config.resolve.alias = Object.assign({'@': './'},
  require('./var/whatever/bundle-map.json'));

module.exports = config;

from webpack-encore.

harentius avatar harentius commented on May 21, 2024 6

Thanks a lot all for clarification, but approach with storing pre-compiled assets in vendor bundles still not fully clear.

  1. How to deal with manifest file? (which theoretically should be used for versioning, but in vendor case it is not possible to use assets without it at all).
    It is not possible to register a multiple manifest files (correct me if I am wrong) which creates some extra headache (create some mechanism to use multiple manifests)
  2. PublicPath parameter also disturbs me as this means that vendor bundle should predict path where assets installed (ok, typically it is bundles/bundlename, and this is not configurable behavior, so this "hardcode" way will work fine. Here more philosophical uncertainty is that correct that I should know logic of the assetic component to use encore)

from webpack-encore.

wasinger avatar wasinger commented on May 21, 2024 6

I just published a bundle providing the commands proposed in my previous comment: https://packagist.org/packages/wasinger/bundle-asset-provider-bundle

Provided commands:

  • assets:sources: Copy or symlink all assets folders from installed bundles to assets/bundles/<bundle-name> in the project root dir.

  • assets:dependencies: Look for package.json files in bundles, compare dependencies to the project's package.json file and tell about missing or conflicting dependencies.

No npm packages are installed and no assets are going to be included automatically; it's the responsibility of the project's developer to install the missing dependencies via npm or yarn and to include the provided assets from the assets/bundles/bundle-name folder into the webpack build pipeline.

I would like to see those commands included in Webpack Encore...

from webpack-encore.

TheCelavi avatar TheCelavi commented on May 21, 2024 5

Auto-configuration of assets with encore is definitely the thing that I would prefer as well. Kinda expected that encore would be somehow coupled with SF Flex, which would, with bundle installation, add assets configuration as well.

I do agree with @Growiel - we have to have sufficient amount of control, that is, to opt-in or opt-out from certain assets inclusions.

Since Flex is "easy install and configuration" system - somehow, bridging/integrating encore with flex seams reasonable.

Example: I am a vendor of DateTimePickerBundle, it has PHP code, Twig code, JS and CSS. When installed with Flex, it should be auto-configured with reasonable defaults and assets included - since, naturally, in order bundle to work, all those are required. However, you maybe don't like my CSS, and you want to exclude it from configuration - and that seams like common use case scenario.

So, both @dkarlovi and @Growiel are right, it should be auto-configured with bundle installation with reasonable defaults, it should be 100% configurable.

How awesome that would be!

from webpack-encore.

stof avatar stof commented on May 21, 2024 4

@weaverryan to use FOSJsRoutingBundle in a CommonJS environment, the gotcha is that you need to configure the router before using it (and that it defines a global variable). This is solved easily by having a module in your project responsible for that, and having all your other code requiring your module instead of requiring the router directly:

// backend_router.js

// Use the webpack feature allowing to read some variable: https://webpack.github.io/docs/shimming-modules.html
const { router, setRoutingData } = require('imports-loader?window=>{}!exports-loader?router=window.Routing,setData=fos.Router.setRoutingData!../vendor/friensofsymfony/js-routing-bundle/Resources/public/js/router.js');
 // dumped_routes.json is the output file for the fos:js-routing:dump command
const routerConfig = require('../dumped_routes.json');

setRoutingData(routerConfig);

modules.exports = router;

and then in your code:

const router = require('./backend_router.js');

const url = router.generate('welcome', {}, true);

however, I agree that this will be easier once we have CommonJS support in FOSJsRoutingBundle, to simplify the loading of the router.

from webpack-encore.

dkarlovi avatar dkarlovi commented on May 21, 2024 4

Shouldn't Encore generate the loader paths for you from your installed bundles?

from webpack-encore.

stof avatar stof commented on May 21, 2024 3

@javiereguiluz Webpack has an option to hook into the resolving, by allowing to define aliases for the module resolution. We could expose a way to use them, to allow defining an alias pointing to a custom location (which could be vendor/friensofsymfony/js-routing-bundle/Resources/... for instance)

from webpack-encore.

Growiel avatar Growiel commented on May 21, 2024 3

I strongly disagree with @dkarlovi's idea.

Sometimes I install bundles to use only their backend stuff or extend them and I 100% don't want their JS/CSS files to make mine bigger by being "auto required".

If I want them, I can require them in my main.js or put them in my vendor.js by using the shared strategy, unless I'm missing something.

from webpack-encore.

harentius avatar harentius commented on May 21, 2024 3

What about bundles that provide stand-alone functionality? (Just for example, SonataAdminBundle)
I agree with @weaverryan that it is logically to require vendor *.js which used in project only by purpose and there is no reason to auto discover such assets.
But is there any ideas how to use encore in bundles like SonataAdminBundle if vendor bundle uses assets itself, providing its pages ?
Theoretically, it should be a way to discover bundles encore config and compile assets, so they can be used in vendor templates.

from webpack-encore.

mvrhov avatar mvrhov commented on May 21, 2024 2

My original sentence on the slack was something along the lines that I expected the encore to be something like maba/webpack-bundle or hostnet/webpack-bundle. So that the assets could be specified in the templates just like now.

from webpack-encore.

d42ohpaz avatar d42ohpaz commented on May 21, 2024 2

Here's my solution that I'm using to making bundle assets available:

package.json

Node is kind enough to run any script before the script if you prefix pre to it. In this case, we want to install a symlink of our bundle assets into the ./assets folder. Why the ./assets folder? For my needs, it didn't make much sense to put it in the default ./public folder because these are not the final versions of the assets.

{
    ...
    "scripts": {
        ...
        "prewatch": "bin/console assets:install --symlink --relative ./assets",
        "watch": "encore dev --watch"
    }
}

webpack.config.js

The first thing to do is to add a little code that will iterate through ./assets/bundles and create both an entry and an alias for each bundle's assets. For my needs I felt that import'ing stylesheets from the Javascript is easier for us to maintain. There is no technical reason why you couldn't use addStylesEntry() in conjunction with encore_entry_link_tags(). YMMV.

Encore
    .addEntry('app', path.resolve(__dirname, './assets/js/main.js'))
    .addAliases({app: path.resolve(__dirname, './assets/')})
    ...
;

const bundlesPath = path.resolve(__dirname, 'assets/bundles/');
const bundles = fs.readdirSync(bundlesPath);
for (let i = 0; i < bundles.length; ++i) {
    const bundle = bundles[i];
    Encore
        .addEntry(bundle, path.resolve(bundlesPath, bundle, 'js/main.js'))
        .addAliases({[bundle]: path.resolve(bundlesPath, bundle)});
}

The second, and most important step in your webpack.config.js is to disable resolving symlinks. I do not know for sure why, but webpack will not be able to read your bundle assets as symlinks (maybe for security). The one caveat I don't have a solution for is if you're developing an npm module parallel to your symfony app and bundles. In other words, using npm link will stop working.

...

module.exports = Encore.getWebpackConfig();
module.exports.resolve.symlinks = false;

index.html.twig (or somewhere reasonably similar)

The important takeaways here are:

  1. You call encore_entry_link_tags and encore_entry_script_tags for your main app
  2. You give your bundles a means of adding their own so it's loaded when the main app loads (i.e., via block statements)
<html>
 <head>
        {{ encore_entry_link_tags('app') }}
        {% block stylesheets %}{% endblock %}
 </head>
 <body>
        {% block body %}{% endblock %}

        {{ encore_entry_script_tags('app') }}
        {% block javascripts %}{% endblock %}
 </body>
</html>

bundles/my-bundle/Resources/views/index.html.twig

Just be sure you get into the habit of calling {{ parent() }} from your blocks so you don't accidentally override other bundles.

{% extends 'index.html.twig' %}

{% block stylesheets %}
       {{ parent() }}

      {{ encore_entry_link_tags('mybundle') }}
{% endblock %}

{% block javascripts %}
    {{ parent() }}

    {{ encore_entry_script_tags('mybundle') }}
{% endblock %}

{% block body %}
    ...
{% endblock %}

from webpack-encore.

fvsch avatar fvsch commented on May 21, 2024 1

I empathize with the desire to get autoloading of front-end code, but as a front-end developer I clearly don’t want that happening, even with opt-out, for three reasons:

  1. Performance: an application may have dozens of bundles with front-end assets, but those may only be required on specific pages, admin pages, public pages, specific sections, etc. Loading everything can kill performance really quickly. It’s not like PHP class autoloading where you build a class map (which is cheap) and only incur the real costs if you actually use a class… with most front-end assets you will send everything down the wire to browsers.
  2. Compatibility: loading different pieces of CSS or JS without carefully checking that they don’t interact badly = broken pages and features.
  3. Loading strategies: different assets may need to be loaded in different ways: injected in a page, referenced as a URL, with require.js, imported with ES6 syntax by webpack and/or Babel, compiled from Sass/Less/etc. to CSS, etc. Some front-end components may need the ability to request additional assets on-demand (images, CSS, JSON or JS for translations or dynamically enabled features). Given those wildly different requirements, I don’t see autoloading happening ever.

You need to manage loading your front-end dependencies yourself, either from bundles or from node_modules or from bower_components or from hard copies. You’re probably already doing that in your templates, with Assetic, with Gulp or webpack, etc., and often a combination of tools and methods. Encore can’t change the game here.


As an aside: as far as I know, Symfony doesn’t a standard way of declaring assets in configuration, like e.g. Drupal 8 does (with its “libraries” config). If it had one, and your app and required bundles used it, you could then output a list of known assets (e.g. as JSON):

{
  "somecomponent": {
    "javascript": {
      "main": "vendor/my-vendor/my-bundle/src/Resources/public/js/somecomponent-main.js",
      "lang_fr": "vendor/my-vendor/my-bundle/src/Resources/public/js/somecomponent-lang-fr.js",
      "lang_de": "vendor/my-vendor/my-bundle/src/Resources/public/js/somecomponent-lang-de.js"
    }
  },
  "othercomponent": {
    
  }
}

(or some other format) and then consume it in Encore or other tools (standard webpack config, gulpfile, etc.). Then you could choose to e.g. concatenate all the JS to one big file and serve it to browsers, though that would probably break horribly for reasons I described before. Or you could use it to create webpack aliases, or to require specific assets (e.g. require(assets.somecomponent.javascript.main) in webpack, or gulp.src(assets.somecomponent.javascript.main) in gulp).

That would be fun, but does not exist in the Symfony world unless I’ve missed it.

from webpack-encore.

Lyrkan avatar Lyrkan commented on May 21, 2024 1

@harentius I'm not sure that handling assets for that kind of vendor should be done by the project using it. It would make more sense for the vendor to directly include a pre-compiled version of them.

from webpack-encore.

oscherler avatar oscherler commented on May 21, 2024 1

@harentius I agree that vendors should include a pre-compiled version of theirs assets. But you still need to add them to your layout so they’re loaded, and you need to concatenate them with the rest of your assets so they don’t generate a gazillion HTTP requests.

from webpack-encore.

mvrhov avatar mvrhov commented on May 21, 2024 1

I do not agree with that the vendors should provide minimized versions!
Whole build should be done by the developer using the bundle. This is the only way that the build files could be optimized properly

from webpack-encore.

mechanicalgux avatar mechanicalgux commented on May 21, 2024 1

Let's say you have this kind of setup:

  • code/demo-app (Symfony app)
  • code/my-bundle

Now I want to code my-bundle assets while testing in demo-app, but I don't want to install all bundle's node dependencies into my demo-app.

Solution, in webpack.config.js of my-bundle:

    .setOutputPath('src/Resources/public/build/')
    .setPublicPath('/bundles/my-bundle/build')
    .setManifestKeyPrefix('/bundles/my-bundle/build/')

Don't forget to install your assets with symlink in demo-app:

php bin/console assets:install public --symlink

Works with build, dev and dev --watch, however it doesn't work with dev-server as the manifest is not allowed to differ from the output path.

Problem solved.

from webpack-encore.

mvrhov avatar mvrhov commented on May 21, 2024

The way we do things ATM is that we have a few common bundles e.g customer, account, messaging, which come with the default set of the assets js/less.
The bundles are then extended in app if needed. In our case the common bundles cover 90% of use cases.

from webpack-encore.

weaverryan avatar weaverryan commented on May 21, 2024

Hi guys!

You can load assets from anywhere. Either in webpack.config.js:

.addEntry('main', './src/SunShine/FooBundle/Resources/public/js/foo_sunshine.js')

Or also by requiring it in a .js file:

// src/SunShine/BarBundle/Resources/public/js/app.js
// you need to go up a few directories, but it's a straightforward path
require ('../../../../FooBundle/public/js/foo_sunshine.js');

So technically, I don't think there's an issue. Stof is totally right about being able alias paths for modules: https://webpack.js.org/configuration/resolve/. We can add a hook to allow these to be added (actually, you can already do it by just adding this key manually to the bottom of your webpack.config.js). But it's not strictly needed.

Btw, about FOSJsRoutingBundle, iirc, due to how that JS file is built, I think requiring it as a module is still a bit of a pain.

from webpack-encore.

weaverryan avatar weaverryan commented on May 21, 2024

@dkarlovi can you say more about what you mean by that? Perhaps show a "fake code" example of how you'd expect it to work? There seem to be a lot of questions about assets in bundles... but these are just assets in different directories, which you can of course import. I feel I may not be understanding the requirement that some people have :)

from webpack-encore.

trsteel88 avatar trsteel88 commented on May 21, 2024

I think what a lot of people are after is automation with bundles. This probably stems from assetic and having it "compile" everything from templates.

A bundle may have twig templates that have a parent () override for a block named javascripts. When you install the bundle all the js for those templates work out of the box.

This is great for utility bundles that many organisations may have for FormTypes ( think date pickers, recaptcha etc)

from webpack-encore.

fvsch avatar fvsch commented on May 21, 2024

I think what a lot of people are after is automation with bundles.

I'm not sure that's what the OP had in mind, and automation can mean many different things.

from webpack-encore.

dkarlovi avatar dkarlovi commented on May 21, 2024

@TheCelavi totally agree. In my mind, bundles should be able to ship their Encore setup (similar to composer.json autoload part which explains to Composer how to auto-load your specific code) which would fit into your application out of the box by default, but you the developer might want to modify (ie. blacklist) certain bundles (or certain aspects of a bundle) to do so.

This would allow Flex to install the bundle, bundle being installed would hook into existing Encore environment and you're done.

from webpack-encore.

 avatar commented on May 21, 2024

@weaverryan

Per request for examples,

I've a SF3.3 project.

Layout includes

	...
	assets/scss
	web/
		js/
		css/
	...

sources, for this example, include

	ls -1 assets/scss
		main.scss
		_variables.scss
	ls -1 node_modules/foundation-sites/scss/{,settings/}*.scss
		node_modules/foundation-sites/scss/foundation.scss
		node_modules/foundation-sites/scss/_global.scss
		node_modules/foundation-sites/scss/settings/_settings.scss

where

	cat main.scss
		...
		@import  'variables';
		@import  'settings';
		@import  'foundation';
		...

In my prior gulp environment, specifying includePaths -- additional to defaults -- worked for multiple dirs,

	var gulp         = require('gulp');
	var sass         = require('gulp-sass');
	...
	gulp.task('scss-min', function(cb) {
	    ...
	        sass({
	            includePaths: [
	                './node_modules/foundation-sites/scss/settings/',
	                './node_modules/foundation-sites/scss'
	            ],
	    ...

On gulp task exec aggregation/minification of @import'd files was OK with with NO full/relatives required in the .scss parents

But, in webpack/encore, exec fails, not finding the PATH-less @import-s

	./node_modules/.bin/encore dev
		Running webpack ...

		 ERROR  Failed to compile with 2 errors                                              18:18:00

		 error  in ./assets/scss/main.scss

		Module build failed:
		@import  'settings';
		^
		      File to import not found or unreadable: settings.
		Parent style sheet: stdin
		      in /work/www/sf/assets/scss/main.scss (line 16, column 1)
		...

editing

	edit main.scss
		...
		@import  'variables';
-		@import  'settings';
+		@import  '~/foundation-sites/scss/settings/settings';
-		@import  'foundation';
+		@import  '~/foundation-sites/scss/foundation';
		...

cures the problem -- for those specific @import-s

Ideally, rather than editing the .scss, pointing at file-paths, a webpack/encore equivalent of directory search paths,

	sass({
	       includePaths: [ ...

consolidated in the webpack.config.js would be helpful.

Reading above, I don't see a finalized/agreed upon approach. Whether that's using Aliases, or some other approach, I'm open.

from webpack-encore.

TheCelavi avatar TheCelavi commented on May 21, 2024

@fvsch So you don't want it - but because of the fact you don't want it, it should not be available and optional either?

  • Performance: edge case, applicable in medium to large applications. Stated issue does not exists if autoconfig is opted out.
  • Compatibility: edge case as well, common practice is that library holds and uses latest dependencies. If issue exists, it will be spotted immediately after bundle is installed. Stated issue does not exists if autoconfig is opted out or configuration is fully customisable after installation.
  • Loading strategy: same as performance.

Purpose of encore and flex is to enable full RAD support, with possibility to reconfigure everything/opt out from everything.

Sorry, but you are clearly missing the point of stated tools. And you are clearly missing the fact that whatever decision is made here, it does not affect you to use whatever tool you want and use - since you can opt out from every tool discussed here.

We want RAD tool, for front end development world as well. In use cases in which tool is failing, we want to be able to reconfigure and fix manually. In other cases - to opt out easily. None of what you have stated is a deal breaker here not to get that tool.

from webpack-encore.

fvsch avatar fvsch commented on May 21, 2024

I stand by what I wrote, but it seems we’re getting sidetracked from the original issue here. The original question was about being able to get assets from bundles. Quoting the OP:

On Symfony Slack some people are concerned about Encore and bundles' assets. The issue is that Encore expects all assets to be stored in the same location. What about in-app bundles then? And what about third-party bundles?

The basic answer is that if you put your webpack config at the root of your project, you can require JS, CSS etc. from vendor/… and from src/… by using complete paths. For example:

// assets/app.js
// (defined as my main entry point in webpack.config.js)
require('src/Something/MyBundle/Resources/public/lib/whatever/whatever.js');
require('src/Something/MyBundle/Resources/public/lib/whatever/whatever.css');
require('vendor/pinano/select2-bundle/Resources/public/js/select2.min.js');
require('vendor/pinano/select2-bundle/Resources/public/js/i18n/es.js');

The expanded answer is that it might be useful to offer a ways to treat bundle names as aliases, so that you don’t have to provide the full path to a bundle, but that offering this convenience on the Node.js side would require some work on the PHP side as well, to provide a map of installed bundles with their names and paths. For instance, Symfony 3.3/4 could write a etc/bundles-paths.json alongside etc/bundles.php:

{
  "FrameworkBundle": "vendor/symfony/framework-bundle"
}

And that could be loaded from your webpack.config.js and Encore could have a method for defining @[bundle_name]/ as a webpack alias, making it easier to require stuff from bundles.

In any case, this would require a PHP script, either as an addition to the Asset component or as a standalone dependency.

From my understanding, this is the scope of this issue (with the whole aliases thing being just an idea that the Encore team may not want at all). “How to enable Rapid Application Development for the frontend in Symfony” is a whole other topic, and is imo far beyond the scope of @symfony/webpack-encore.

from webpack-encore.

TheCelavi avatar TheCelavi commented on May 21, 2024

“How to enable Rapid Application Development for the frontend in Symfony” is a whole other topic, and is imo far beyond the scope of @symfony/webpack-encore.

You are right, lets correct that: symfony/flex#102

It's a very young package, we are pitching ideas.

In regards solely to this topic, bundle locator syntax (@BundleName) seams quite logical approach, it is used by Twig, SF configuration (routing,services...etc..), etc...

from webpack-encore.

 avatar commented on May 21, 2024

Fair point re: right comment(s) in right thread.

That said, 'my' comment, above, suggests the option to specify additional include/search paths that'll be followed during aggregation. So as to find 'pathless' @import-s, for example.

Again, easily available in gulp.

Does that appropriately belong as part of this^ discussion?

from webpack-encore.

dkarlovi avatar dkarlovi commented on May 21, 2024

@fvsch point is: you always have the option to NOT use the auto-enabler in your project and basically ignore Encore completely. This way, you install "dozens of bundles with frontend assets", they ship their Encore config, but your app doesn't care as it doesn't use it.

The way I see it, Encore should solve most common use cases for most people by default, allow for some flexibility and more advanced usage (whitelisting / blacklisting, opt out, etc) and for people to not use it. But, if you're always required to mess around with Webpack config anyway, Encore might not be worth the effort at all, you drop a lot of opportunities for RAD.

from webpack-encore.

 avatar commented on May 21, 2024

Comming back to the idea of autoproviding assets from bundles...

I have just started with webpack a few days ago. Is there a way allready to autoprovide assets?

I could help myself with a composer postinstall script which parses the bundle for scripts/css inside Resources/public/js and css folder and adds

.addEntry('app', './vendor/namespace/module/foo/bar/Resources/public/js/[scriptname].js')

to webpack.config.js lets say after the last addEntry(... and for css the last addStyleEntry(... line - if there is one

I simply don't want to do ANYTHING after composer require(vendor/bundle). Actually i want to create an installer for Packages to be used inside of my application based on composer...

from webpack-encore.

oscherler avatar oscherler commented on May 21, 2024

Loading assets from bundler should not depend on where the bundle is installed. Today it can be installed by Composer in vendor/acme/paginator, or as a submodule in lib/, or just sit in your src/ folder. Tomorrow it can move to vendor/acme/acme, or your submodule or bundle in src/ can become a Composer package…

from webpack-encore.

harentius avatar harentius commented on May 21, 2024

@Lyrkan thanks, this is a possible solution.
Here still some minor worries (more like thoughts in loud).

  1. Ok, we build assets to some location under Resources/public, but than we should use some way to install them. I thought that AssetsInstallCommand should not be used with Encore approach, but here we are again then.
  2. Built assets will include a tons of vendor (js) code (which is actually normal for build releases in js-world)

from webpack-encore.

oscherler avatar oscherler commented on May 21, 2024

So if I use a vendor, I have configure my frontend toolchain with Babel, CoffeeScript, TypeScript, WhateverEsotericTranspilerSomeoneDecidedToPlayWith even though I don’t use them?

Do you realise what you’re saying?

from webpack-encore.

fvsch avatar fvsch commented on May 21, 2024

Folks, we’re never going to get consensus on this. Even in the Node.js ecosystem, which has a much stronger focus on front-end JS (downloads from npmjs.com skew hugely towards frontend packages), there is no agreed-upon answer to these questions:

  • If the source is ES6, should the package include a ES5 build too? (Most packages do, but not all.)
  • Should the package include a minified JS build as well as the sources? (Many packages do, but not all.)
  • Where should "built" scripts live in the package? (Conventions range from ./ to ./dist/ to ./lib/ or even to ./src/…)

The only convention is for what file gets required when you do require('some-installed-package'), and even that is a bit in flux for ES Modules.

So, on the PHP/Composer/Symfony side, it would be useful if Symfony provided guidelines for bundles that want to provide (optional or mandatory) frontend code, but don’t expect them to be followed all the time. As a result, don’t expect Symfony Encore to automagically be able to load this frontend code, because even if conventions exist they will be broken all the time. Everyone is going to have to do this a bit manually.

So if I use a vendor, I have configure my frontend toolchain with Babel, CoffeeScript, TypeScript, WhateverEsotericTranspilerSomeoneDecidedToPlayWith even though I don’t use them?

No, and vendors should probably include ES5 builds (minified and unminified). But if they rely on ES6 features and libs like React, VueJS etc, and polyfills for ES6 and other browser features, then this ES5 build will include a lot of runtime stuff that will make it huge. If 3 vendors do that, you end up paying the price of the polyfills and libs 3 times, possibly with JS conflicts breaking your pages too.

But that’s already a problem with vendors that require and include jQuery, Bootstrap, Modernizr and a bazillion dependencies. It’s cool if you only use this vendor in your pages and not 2-5 others plus your own Bootstrap build etc. In practice it’s often a mess, and vendors which come with many frontend dependencies should be avoided like the plague if they’re only responsible for a widget that you want to use in your pages (rather than for full views).

So it’s not exactly a new problem. And there is no one-size-fits-all solution.

IMO, a vendor which provides a big frontend feature should include several scripts:

  • One for each library or third-party (OSS) script they use; OR instructions on how to install those dependencies with e.g. npm.
  • Their own script(s), without those third-party dependencies.

And they should document how to require all those scripts with different build tools; a section on adding stuff directly in HTML (with <script src="…"></script> tags), one on Assetic and one on Encore should be enough, especially since the Encore section will probably use full paths like "vendor/my-vendor/my-bundle/src/Resources/public/js/my-bundle-feature.js", or alternatively symlinked paths like "web/myvendormy/js/my-bundle-feature.js".

from webpack-encore.

wasinger avatar wasinger commented on May 21, 2024

I see this is quite an old discussion, but still an open issue... I came here while searching for a solution to provide some javascript in a bundle that should be included in the Webpack-Encore pipeline (it's the use case others mentioned here: I have a private bundle providing special form types that is shared between my projects).

My proposed favorite solution would be the following:

  • The asset sources of the bundle should live in an assets folder inside the bundle just like it is in the project

  • There is an assets:install-sources command just like the well-know assets:install that symlinks or copies the assets folder from the bundle to the project's assets/bundles/bundle-name folder

  • In the projects's assets/js/app.js file or any other webpack entry point, the project builder can just include the assets from the ../bundles/bundle-name/ folder, e.g. import "../bundles/bundle-name/js/index.js".

  • The javascript package dependencies of a bundle should be defined in a package.json file in the root folder of the bundle. Another command assets:check-dependencies should be created that compares the dependencies of all bundles with the project's package.json file and suggests to install missing packages in the project (or warn about incompatible version requirements). Maybe there could also be the option to automatically update the projects package.json file if there are no conflicts.

This way, no Javascript from bundles will be automatically injected into the project. But there would be a well-known convention for bundle authors to provide javascript moduls and other assets on the one hand, and for project builders to include those assets into their webpack-encore build on the other hand.

from webpack-encore.

gseidel avatar gseidel commented on May 21, 2024

Since handling assets in symfony is moved to webpack (and therefor to javascript) for valuable reasons, in my opionen, provider of third party bundles should following this way consistently.

In this issue, there are some approches that depend on PHP code, like JS looking up for bundle paths or PHP looking up for package.json files, etc.

I would prefer a solution:

  • without dependencies on PHP
  • use the power of javascript and NPM
  • leave full control to the developer
  • easy to install

A solution could be on the bundle project:

/node_modules <-- Third party dependencies
/assets <-- Could be also anywhere in the provider bundle
  /node_modules
    /my_bundle_package <-- The code you want to provide
      /index.js
      /my_code.js
      /package.json <-- Put your dependencies
  /entry.js
/package.json <-- Copy or merged file of your packages
// entry.js
// This code should keep as simple as possible (like config files)
// The path will be resolved correctly without configuration, because node
// will go up on the directory path to search for node_modules/my_bundle_package 

const my_package_loader = require('my_bundle_package');
my_package_loader.load()
// webpack.config.js

Encore.addEntry('./assets/entry.js', 'entry')

The my_bundle_package should be pushed to NPM


Then the user code would look like:

// package.json

...
  "my_bundle_package": "^1.0"
...
// entry.js
// same code as the providers bundle

 const my_package_loader = require('my_bundle_package');
 my_package_loader.load()
// webpack.config.js

Encore.addEntry('./assets/entry.js', 'entry')

So the bundle asset code is loaded by webpack over node_modules and all dependencies of my_bundle_package are loaded correctly as well, because it's handled by the package manager.

It's also not to difficult to install and flex could handle the package.json and the copy of entry.js in future.

The user is also able to modify the entry.js in order to add some plugin code, load an adapter you may provide or merge it with his entry point

And there is no dependency to PHP

The disadvantages i see so far are:

  • The bundle provider has more overhead
  • Updating bundles means also updating package.json, which could be tricky

from webpack-encore.

mvrhov avatar mvrhov commented on May 21, 2024

my_bundle package cannot be pushed to NPM! Please note, that most projects that use symfony are closed source.

from webpack-encore.

lainosantos avatar lainosantos commented on May 21, 2024

Hello,

any solution for third-party bundles's assets?

from webpack-encore.

piotrkochan avatar piotrkochan commented on May 21, 2024

problem still not resolved

from webpack-encore.

taleteller avatar taleteller commented on May 21, 2024

@9ae8sdf76 Your approach is interesting, but how do manage to override the index.html.twig from Bundles without ending up in an infinite recursion? If I try it your way I end up with Maximum function nesting level of '256' reached, aborting!. Overriding them using an Namespace like @!Namespace/... gives me the first registering bundle only.

I presume you registered the Bundle paths in twig / path config, otherwise they get ignored for me entirely.

from webpack-encore.

MichaelBrauner avatar MichaelBrauner commented on May 21, 2024

Hi guys!

I have a running bundle in its own directory. The assets are generated by webpack-encore in the parent symfony project:

Encore .setOutputPath('../../Bundles/RockCoreBundle/public/') .setPublicPath('/')

For now my new bundle accepts all entrypoints:

{{ encore_entry_link_tags('tailwind', null, 'backend') }}

Is it just that easy? Or is my approach wrong?
I mean, at least I should do the generation of the assets directly inside the bundle itself right?

from webpack-encore.

d42ohpaz avatar d42ohpaz commented on May 21, 2024

Encore .setOutputPath('../../Bundles/RockCoreBundle/public/') .setPublicPath('/')

The problem comes up when working on a team, and doing it this way means that not only does your test/production sites have to have this file structure enforced, but so does your team. And if there's one thing I've learned in all my years: people guard their coding preferences more closely than they do their command-line text editor (vim4life!).

Now if there were some way to maybe bridge the gap between composer.json and webpack, then we could take advantage of the autoload-dev for finding bundles. The great thing is, composer.json is already in JSON.

We could even go so far as to add something to the extra section that could dictate the public path and output path as a whole; minimize the need to edit webpack.config.js.

from webpack-encore.

d42ohpaz avatar d42ohpaz commented on May 21, 2024

@taleteller
My apologies for such a late reply! I don't know how I missed your questions.

how do manage to override the index.html.twig from Bundles without ending up in an infinite recursion?

I'm not entirely sure I understand what you're doing, but I'll try my best.

My base index.html.twig is set up to take advantage of blocks for the things I wish to override/extend (javascript, stylesheets, title, language, icons, body, header, footer, etc). Then in my bundles, I extend the index.html.twig and override the blocks. I do not override my template, for the very reason you stated: infinite recursion.

I also treat each bundle as a separate entity that only has knowledge about itself; in the rare circumstance there needs to be a bridge between two bundles, I keep it minimal and out of my templates.

For example, I create an endpoint that simply forwards the request to the appropriate bundle. This allows me to minimize changing my templates and forcing changes in the controller only - MVC style.

I presume you registered the Bundle paths in twig / path config, otherwise they get ignored for me entirely.

I didn't register bundle paths with Twig. I use the autoload-dev in composer.json to tell composer where my bundles are, then I add the necessary line in config/bundles.php, and if necessary, I'll add a section to config/routes.yaml so my endpoints get registered.

from webpack-encore.

MichaelBrauner avatar MichaelBrauner commented on May 21, 2024

The problem comes up when working on a team, and doing it this way means that not only does your test/production sites have to have this file structure enforced

When I (composer) require webpack encore - I could give a webpack.config.js into the bundle to generate the assets inside of the bundle.

That should not affect the coding preferences of others much, isn't it?

from webpack-encore.

javiereguiluz avatar javiereguiluz commented on May 21, 2024

Let's close this issue. We haven't resolved it in almost 6 years ... and nothing serious has happened. We've built lots of apps using Webpack Encore during this time. So, things are fine. Thanks.

from webpack-encore.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.