Comments (45)
@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:
- I install the bundle
- Encore figures out that it's there and how to expose its assets to Webpack
- Webpack does what ever it needs to
- Stuff works for me (the developer) and my end users without me figuring out Webpack
from webpack-encore.
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:
- either a simple
'@vendor/'
(and then you're on your own for looking up the exact paths); - or a
@/
alias that matches the root of the project (like some JS frameworks do for thesrc
folder, exceptsrc
in those frameworks does not match thesrc
folder in Symfony 3, let alone Symfony 4, so root is better); - 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.
Thanks a lot all for clarification, but approach with storing pre-compiled assets in vendor bundles still not fully clear.
- 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) - 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.
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 allassets
folders from installed bundles toassets/bundles/<bundle-name>
in the project root dir. -
assets:dependencies
: Look forpackage.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.
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.
@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.
Shouldn't Encore generate the loader paths for you from your installed bundles?
from webpack-encore.
@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.
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.
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.
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.
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 thatimport
'ing stylesheets from the Javascript is easier for us to maintain. There is no technical reason why you couldn't useaddStylesEntry()
in conjunction withencore_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, usingnpm 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:
- You call
encore_entry_link_tags
andencore_entry_script_tags
for your main app- 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.
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:
- 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.
- Compatibility: loading different pieces of CSS or JS without carefully checking that they don’t interact badly = broken pages and features.
- 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.
@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.
@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.
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.
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.
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.
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.
@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.
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.
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.
@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.
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.
@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.
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.
“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.
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.
@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.
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.
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.
@Lyrkan thanks, this is a possible solution.
Here still some minor worries (more like thoughts in loud).
- 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.
- Built assets will include a tons of vendor (js) code (which is actually normal for build releases in js-world)
from webpack-encore.
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.
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.
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-knowassets:install
that symlinks or copies theassets
folder from the bundle to the project'sassets/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.
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.
my_bundle package cannot be pushed to NPM! Please note, that most projects that use symfony are closed source.
from webpack-encore.
Hello,
any solution for third-party bundles's assets?
from webpack-encore.
problem still not resolved
from webpack-encore.
@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.
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.
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.
@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.
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.
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)
- imports are ignored HOT 9
- unplugin-vue-i18n destroy all my images and fonts
- asset/inline Asset Module complains about generator property which isn't there
- webpack-encore not working correctly in a live server
- how to add plugins HOT 1
- HMR not working with custom domain HOT 1
- How can I transpileDependencies when using webpack encore
- Debugging hanging CSSMinimizerPlugin
- Module build failed: Module not found: "@symfony/stimulus-bundle" HOT 2
- Allow to pass options to babel react preset
- Twig file changes are not working with "watch" or "dev-server" HOT 1
- Getting an error for assets compilation with webpack-encore.
- ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined HOT 2
- Disabling notifications on windows breaks --watch flag HOT 1
- Warning on sass-loader 14 HOT 1
- Svelte loader Module not found
- Two different builds for two versions of Vue.js app HOT 3
- Warning for postcss-loader v8.1.0 to be too new HOT 3
- PrettyError not supported anymore results in an error HOT 3
- Fully support less-loader ^12 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from webpack-encore.