This question already has answers here:
Webpack FOSJsRoutingBundle integration with Symfony Flex and Angular
(2 answers)
Closed 4 years ago.
The issue is that I cannot get FOSJsRoutingBundle to work with Symfony Flex and Webpack.
I've been using this bundle in Symfony 3 for a long time and there's never been an issue but with the introduction of webpack, the setup has become more complex. Unfortunately the documentation for version 2.2 isn't clear.
You can find the current documentation for the bundle here: https://symfony.com/doc/master/bundles/FOSJsRoutingBundle/index.html
As you can see it recommends the following approach for Symfony Flex, so I'm writing this in code/assets/js/fos_js_routes.js:
const routes = require('../../public/js/fos_js_routes.json');
import Routing from '../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.js';
Routing.setRoutingData(routes);
with a test route in: code/assets/js/fos_routing_test.js
Routing.generate('test_route');
and then including it in webpack.config.js as:
.addEntry('app_fos_routing', [
'./assets/js/fos_js_router.js'
])
.addEntry('app_fos_generate_routes', [
'./assets/js/fos_routing_test.js'
])
and my code/templates/index.html.twig:
{{ encore_entry_script_tags('app_fos_routing') }}
{{ encore_entry_script_tags('app_fos_generate_routes') }}
However when I implement this webpack creates the following which causes a reference error ReferenceError: Routing is not defined
/***/ "./assets/js/fos_js_router.js":
/*!************************************!*\
!*** ./assets/js/fos_js_router.js ***!
\************************************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _vendor_friendsofsymfony_jsrouting_bundle_Resources_public_js_router_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.js */ "./vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.js");
/* harmony import */ var _vendor_friendsofsymfony_jsrouting_bundle_Resources_public_js_router_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_vendor_friendsofsymfony_jsrouting_bundle_Resources_public_js_router_js__WEBPACK_IMPORTED_MODULE_0__);
var routes = __webpack_require__(/*! ../../public/js/fos_js_routes.json */ "./public/js/fos_js_routes.json");
_vendor_friendsofsymfony_jsrouting_bundle_Resources_public_js_router_js__WEBPACK_IMPORTED_MODULE_0___default.a.setRoutingData(routes);
/***/ }),
I had the same issue in my Flex application. Here's the steps I took to make it work:
Download FOSJSRoutingBundle and make sure that the generated file in public/bundles/fosjsrouting/js/router.js looks like this.
Generate your routes with the command fos:js-routing:dump --format=json --target=public/assets/js/fos_js_routes.json
Create a JS file where you'll have to use the generated route.
test.js:
import Routing from '../../../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js';
const routes = require('../fos_js_routes.json'); //file with generated routes, created after executing the command above.
Routing.setRoutingData(routes);
Routing.generate('booking_data') //use generated route
//... the rest of your JS code
Make sure that those relative paths are correct.
Add your test.js to your webpack.config.js file:
webpack:
const Encore = require('#symfony/webpack-encore');
Encore
.setOutputPath('public/build')
.setPublicPath('/build')
.setManifestKeyPrefix('')
.splitEntryChunks()
.addEntry('js/test', './public/assets/js/test.js')// JAVASCRIPT
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.enableSassLoader()
.enablePostCssLoader()
.enableSingleRuntimeChunk()
;
module.exports = Encore.getWebpackConfig();
Add test.js to your template
twig:
{{ encore_entry_script_tags('js/test') }}
This is everything that I have done to make it work.
I suggest to change your import to
const routes = require('../../public/js/fos_js_routes.json');
const Routing = require('../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.js');
Routing.setRoutingData(routes);
Related
I'm new to Laravel and I'm trying to compile and upload my resources of video using Laravel Mix.
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
.react()
.sass('resources/sass/app.scss', 'public/css');
And this is the code frontend with the react
import React from 'react';
import Video from '../../videos/video.mp4';
import {HeroContainer, HeroBg, VideoBg} from './HeroElements';
const HeroSection = () => {
return (
<HeroContainer id="home">
<HeroBg>
<VideoBg autoPlay loop muted src={Video} type='video/mp4' />
</HeroBg>
</HeroContainer>
)
}
export default HeroSection;
And this is the result of the output and error
Module parse failed: Unexpected character ' ' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
If you are experiencing the error in the screenshot below, try the following:
Install the raw_loader module:
npm install raw-loader --save-dev
In the webpack.mix.js file use the raw_loader module in a rule that captures the files you want:
const mix = require('laravel-mix');
mix.webpackConfig({ module: { rules: [{ test: /\.mp4$/i, use: 'raw-loader' }] } })
.ts('resources/ts/app.ts', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
For the regular expression to capture more file you can use it as:
/\.(mp4|avi|pdf|mp3)$/i
The error that occurred before using the raw_loader module:
Success using raw_loader module:
Ps: Looks like you're using React. In my example I used Vue.Js 3... but the problem doesn't seem to relate to that.
What I have is an existing laravel application with blades , laravel routes and a few vue components. So I don't want to replace the existing routes with vue router. What I want is to add additional routes without disturbing the existing laravel routes.
For an example I have a category which already is using the following category
Route::get('category/index' , 'CategoryController#index')->name('category.index');
Then I would like to add a new route using vue router without disturbing the category route
For an example:
import Dashboard from "../views/Dashboard.vue";
const routes = [
{
path: "/",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true
}
}
]
Is this possible?
Update: This is what I did (If anyone can point out what am I doing wrong, it would be greatly appreciated)
1.0 Install Vue Router using npm
2.0 App.js (Use Vue Router)
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [
{ path: '/dashboard', component: require('./components/Dashboard')},
];
const router = new VueRouter({
routes, // short for `routes: routes`
mode: 'history',
});
3.0 Web.php
Route::get('/{vue_capture?}', function () {
return view('testing.main');
})->where('vue_capture', '^(?!storage).*$');
4.0 main.blade.php(in testing folder)
#extends('layouts.app')
#section('content')
<div class="container" id="app">
<router-view></router-view>
</div>
#endsection
5.0 It doesn't work
Thank you.
Yes I believe this should be possible.
You will need to add a Laravel route that captures all the vue routes and shows a view which includes the vue routes.
Route::get('/vue/{vue_capture?}', function () {
return view('vue.index');
})->where('vue_capture', '[\/\w\.-]*');
You should be able to include both this route and the original Laravel ones. One option would be to prefix the view routes as shown above with /vue, alternatively if you put the routes in the correct order you should be able to avoid the prefix, if you so wish.
The php artisan route:list command will help you, by allowing you to see what the current routes are.
Yes you can and simple.
All you need is to put the existing route at the top over the route that handles for vue app.
it should look like this.
web.php
// existing route
Route::get('category/index' , 'CategoryController#index')->name('category.index');
// handle vue app
Route::get('{path}', 'VueController')->where('path', '(.*)');
VueController
public function __invoke()
{
reuturn view('index');
}
for working example you can read this section to work with vue-router vue-router
I have a server-side-rendered legacy PHP 5.6 web app that I want to modernise using VueJS
Within the project structure I have set up a new Vue project and set up Vue Router and Webpack with an entry point of main.js
Main.js
Vue.config.productionTip = false
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import router from './router/router'
new Vue({
render: h => h(App),
router
}).$mount('#app')
I am currently inserting VueJS into the legacy app by inserting this code at the bottom of a php file:
<div id="app">
</div>
<script src="http://localhost:8080/js/main.js"></script>
The url of this page is https://www.example.com/user_portal/employee_holiday_info.php#/
However Vue Router recognises it as / because it is the point of entry.
At the moment I have to insert the above code on every PHP file that I want to use VueJS on. Is there a better way of doing this?
If I insert the above code at the bottom of say, index.php then Vue Router would also recognise that page as /. In which case both urls:
https://www.example.com/user_portal/employee_holiday_info.php#/
https://www.example.com/user_portal/index.phpwould render the same Vue component, HelloWorld.
Vue Router
import HelloWorld from "../components/HelloWorld";
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'hello-world',
component: HelloWorld,
}
]
});
export default router;
How can I set this up so I can on multiple Vue components throughout a single php file and share data between them using Vuex.
I have followed the tutorial on how to integrate Vue into Symfony (3.3), and it's working just fine.
I'd like to however use vue-router in HTML5 History mode, so with "real" urls instead of hashes. The problem is while that works well when initially loading the index page, that it won't work to open a page with a Vue URL that symfony doesn't know, cause symfony will throw a 404 error and not load the index view with the Vue app.
I'd like to only use symfony for specific route prefixes, like /blog, /api, and for all other routes load the index route that does nothing but load the vue app, but I don't really know where to start.
I assume I either have to change the .htaccess (currently using the exact one that came with the symfony installation) or somehow "catch" routes symfony doesn't know and redirect to the index page - however I'm stuck here since I'd want routes that are not found within the range of the few route prefixes I want symfony to use to still throw a 404 error.
For those who prefer using annotations [Symfony 3.x, 4.x]
You could use the following Routing in Symfony.
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
* #Route("/{route}", name="vue_pages", requirements={"route"=".+"})
*/
public function indexAction(Request $request)
{
return $this->render('default/index.html.twig', []);
}
}
And In VueJS, you can Vue-Router to display a 404 page for routes not found via a wildcard as shown below,
import '...'; // import required components
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'homepage',
component: home
},
{
path: '/hello',
name: 'hello',
component: hello
},
{
path: '*', // wildcard
name: 'notfound',
component: notfound
}
]
});
You could check this Reference tutorial and the source code for a step-by-step setup.
Tested with Symfony 3.x, 4.x, VueJS 2.5.x, VueRouter 3.x
Had the Same issue. Symfony is simultaneously delivering a Vue driven frontend and implementing an Rest-API. I solved it using some sort of PageNotFound-Fallback, so basically every route that was not found by the Symfony Router will be forwarded/redirected to the Frontend. So the FrontendController looks like this:
class FrontendController extends Controller{
public function indexAction(Request $request)
{
$base=$request->getBaseUrl();
return $this->render('default/index.html.twig',['basePath'=>$base]);
}
public function pageNotFoundAction()
{
return $this->forward('AppBundle:Frontend:index');
}
}
With an additional configuration in the routing.yml (see: Redirect with Event Listener for all "No route found 404 Not Found - NotFoundHttpException")
pageNotFound:
path: /{path}
defaults: { _controller: AppBundle:Frontend:pageNotFound, path: '' }
requirements:
path: .*
Finally, the VueRouter needs to be configured, so it keeps the correct environment, simply by adding the base Property in the Router constructor. If the frontend component is not displayed correctly, you can use router.push('some-route') to manually adjust it.
Keep in mind that there will be no more 404 Errors, since they are all forwarded to the frontend, which can lead to bad scenarios using ajax on page load...
Altough it feels like a hack, I hope this helps. Open for better solutions.
EDIT Symfony version 3.4.3, Vue version 2.5.1
Here i was i have :
A RESTful Symfony API that i created with few bundles
A front AngularJS that i have in the web repository
Now here is a sample of my routing file :
$routeProvider.
when('/liste-produits', {
templateUrl: '../templates/list-products.html',
controller: 'ProductListCtrl'
}).
otherwise({
redirectTo: '/'
});
The fact that i have to use "../". Because otherwise it won't work in dev environnement (app_dev.php). And of course by the time i will post it in production (app.php) i won't need to add this "../"
Do you guys understand my problem ?
Since i can get assetic from Symfony work in the routing file.
How can i solve this ?
There is an approach, where you define a global variable in your base twig file:
Symfony 2:image paths in javascript file with assetic which you can in turn use in e.g. AngularJS.
There is also a bundle called FOSJsRoutingBundle, it sort of exposes your routes to the client and thus javascript. That might be interesting for you.
However there is another option; - I have personally used the approach posted by Rein Baarsma with the twig file and then cached the resulting javascript.
It's fairly simple to write a request listener that renders the twig file to a javascript file once a day or whenever the javascript file is deleted.
I used the same approach with the stylesheets for a project with daily changing colors.
If you do not cache it, the browser will revisit the route returning the javascript on each page and rerender the javascript file, which adds a lot of overhead.
You could simply make a Symfony Controller with a view on a js file. That way you can use the twig (or php) template functions (like twig's path() function) to avoid any strange urls.
In your controller:
public function routingAction(Request $request) {
$this->render('angular/routing.twig.js');
}
And in your routing
$routeProvider.
when('/liste-produits', {
templateUrl: {{ path('product_list') }},
controller: 'ProductListCtrl'
}).
otherwise({
redirectTo: '/'
});