I have followed the steps mentioned in this link for desktop notification in localhost https://pusher.com/tutorials/desktop-notifications-laravel/. and run the command in cli 'npm run dev'.
after running the project using command 'php artisan serve' in live link getting the error
app.js
require('./bootstrap');
Vue.component('home', require('./components/Home.vue'));
webpack.mix.js
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel applications. By default, we are compiling the CSS
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js')
.postCss('resources/css/app.css', 'public/css', [
//
]).vue();
bootstrap.js
window._ = require('lodash');
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});
welcome.blade.php
<!-- ./resources/views/welcome.blade.php -->
<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>News Talk</title>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<style>
.container {
padding-top: 100px;
}
</style>
<!-- Scripts -->
<script>
window.Laravel = {!! json_encode([
'csrfToken' => csrf_token(),
]) !!};
</script>
</head>
<body>
<div id="app">
<!-- home Vue component -->
<home></home>
</div>
<!-- Scripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.12/vue.js"></script>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
when run the command 'npm run dev'
package.json
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
},
"devDependencies": {
"axios": "^0.21",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
"postcss": "^8.1.14",
"vue-loader": "^15.9.7",
"vue-template-compiler": "^2.6.12"
},
"dependencies": {
"laravel-echo": "^1.11.3",
"pusher-js": "^7.0.3",
"vue": "^2.6.12"
}
}
Please help me to solve this issue.
First remove node_modules folder and package-lock file by running rm -rf node_modules/ package-lock.json.
Remove vue dependencies vue, vue-loader and vue-template-compiler from package.json file.
Now run npm install.
Install vue and vue-loader by npm install vue vue-loader file-loader
It will install vue 2.6.13 and vue-loader 15.9.7 and file-loader 6.2.0 version package.
Install npm install vue-template-compiler --save
In app.js file
require('./bootstrap');
import Vue from 'vue';
Vue.component('home', require('./components/Home.vue'));
You don't need to add cdn link in blade file. It will automatically added using webpack
you have missing this window.Vue = require("vue"); in
app.js
window.Vue = require("vue");
require('./bootstrap');
Vue.component('home', require('./components/Home.vue'));
put this on your package.json
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
},
"devDependencies": {
"axios": "^0.21",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
"postcss": "^8.1.14",
"vue-loader": "^15.9.7",
"vue": "^2.5.17",
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"laravel-echo": "^1.11.3",
"pusher-js": "^7.0.3",
"vue": "^2.6.12"
}
}
then run npm run update && npm run dev
I installed a fresh Laravel 8 and Vue-js. upon installing the npm and vue it installs well. Now my problem is when I run the npm run watch then load the page it is a blank white page
step install is
composer create-project laravel/laravel example-app
cd example-app
php artisan serve
composer require laravel/breeze --dev
php artisan breeze:install
npm install
npm run dev
php artisan migrate
my testapp.vue
<template>
<div>
<h1>Hello world! asasasaas</h1>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
my views/testpage.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Testpage</title>
</head>
<body>
<div id="app">
<main-app></main-app>
</div>
</body>
<script src="{{ asset('js/app.js') }}"></script>
</html>
my js/app.js file
require('./bootstrap');
window.Vue = require('vue');
Vue.component('main-app', require('./components/TestApp.vue').default);
const app = new Vue({
el: '#app'
});
my webpack.mix.js
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel applications. By default, we are compiling the CSS
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js')
.postCss('resources/css/app.css', 'public/css', [
// require('postcss-import'),
// require('tailwindcss'),
// require('autoprefixer'),
])
.vue();
route in web.php
Route::get('/test', [TestController::class, 'index']);
Can someone help me figured this thing out? when I load the page it is a blank white page. it seems the vue is not loaded.
I just did a fresh install of Laravel 6.1 and ran
composer require laravel/ui
php artisan ui vue
npm install && npm run dev
But when looking at my page in the browser I see that the Vue component is not displayed and Vue isn't even loaded at all. I have the following errors in my DOM.
Are these the reason that Vue isn't loading? And how do I solve them? The url should be http://localhost/laravel_applications/webgame/public/css/app.css and http://localhost/laravel_applications/webgame/public/js/app.js how can I change this? I'm running it on Xammp and it's in the htdocs folder under /laravel_applications/webgame. I tried changing the APP_URL in the env file to
APP_URL=http://localhost/laravel_applications/webgame/public
but that did not work.
Vue is installed in my project and my app.js looks like this
require('./bootstrap');
window.Vue = require('vue');
import Vue from 'vue';
// const files = require.context('./', true, /\.vue$/i);
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default));
Vue.component('application', require('./components/application.vue').default);
const app = new Vue({
el: '#app',
});
I have an components/application.vue that looks like this
<template>
<div>
Test
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
And a welcome.blade.php that looks like this
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SPA</title>
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<link rel="stylesheet" href="{{ mix('css/app.css') }}" />
<script defer src="{{ mix('js/app.js') }}"></script>
</head>
<body>
<div id="app">
<application></application>
</div>
</body>
</html>
My package.json looks like this
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "npm run development -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.19",
"bootstrap": "^4.0.0",
"cross-env": "^5.1",
"jquery": "^3.2",
"laravel-mix": "^4.0.7",
"lodash": "^4.17.13",
"popper.js": "^1.12",
"resolve-url-loader": "^2.3.1",
"sass": "^1.20.1",
"sass-loader": "7.*",
"vue": "^2.5.17",
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"vue-router": "^3.1.3"
}
}
And this is my mixin file
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
you don't need to put
APP_URL=http://localhost/laravel_applications/webgame/public
laravel has helper asset() which is point to public folder of laravel so anything inside you public dir you can load via asset() function
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SPA</title>
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<link rel="stylesheet" href="{{ asset('css/app.css') }}" />
<script defer src="{{ asset('js/app.js') }}"></script>
</head>
<body>
<div id="app">
<application></application>
</div>
</body>
</html>
ref link https://laravel.com/docs/master/helpers#method-asset
I'm trying to build a PWA for my app; and have spent almost 48 hours trying to figure out how to make use of Workbox with Laravel Mix. What's ironical is that Google says Workbox is meant to make things easy!
Buh!
Okay, so far I've figured out that -
I will need to use the InjectManifest Plugin because I want to integrate Push notifications service in my Service Worker
I have no clue how to specifiy the paths for swSrc and swDest.
What code should go into my webpack.mix.js and whether I should have a temporary service-worker inside my resources/js folder to create a new service worker inside public/ folder.
Can someone help?
PS: I've read almost every blog and help article; but none talks about reliably using Workbox with Laravel mix. Would really appreciate some help here.
I have done a lot of research into this recently and whilst this may not be a full answer to your question, it should give you, or anyone else visiting this page, enough guidance to get started...
I will add to this answer as I learn and research more.
For the purposes of this answer, I will assume your service worker is called service-worker.js, however, you can obviously call it whatever you like.
Step 1 - Laravel Mix
Assuming you are using Dynamic Importing in your project (if you aren't, you should be), you will need to downgrade Laravel Mix to version 3. There is an acknowledged bug in Laravel Mix 4 that prevents CSS from bundling correctly and this will not be fixed until Webpack 5 is released.
In addition, the steps outlined in this answer are specifically configured for Laravel Mix 3.
Step 2 - Import or ImportScripts
The second issue to solve is whether to utilise the workbox-webpack-plugin for injecting the workbox global using importScripts or whether you should disable this (using importWorkboxFrom: 'disabled') and just individually import the specific modules you need...
The documentation states:
When using a JavaScript bundler, you don't need (and actually shouldn't use) the workbox global or the workbox-sw module, as you can import the individual package files directly.
This implies that we should be using import instead of injecting the importScripts.
However, there are various issues here:
We do not want service-worker.js to be included in the build manifest as this will be injected into the precache manifest
We do not want service-worker.js to be versioned in production i.e. the name should always be service-worker.js, not service-worker.123abc.js.
InjectManifest will fail to inject the manifest because the service-worker.js file will not exist at the time that it runs.
Therefore, in order to utilise import instead of importScripts, we must have two separate webpack (mix) configurations (see conclusion for guidance on how to do this). I am not 100% certain this is correct, but I will update my answer once I have received an answer to either of the following (please support them to increase chance of receiving an answer):
How to use Workbox with a Bundler (Webpack etc.)
https://github.com/GoogleChrome/workbox/issues/2207
Step 3 - File Structure
Assuming you are using InjectManifest and not GenerateSW, you will need to write your own service worker which will have the JS manifest injected into it by the webpack plugin on each build. This, quite simply, means you need to create a file in your source directory that will be used as the service worker.
Mine is located at src/js/service-worker.js (this will be different if you are building in a full Laravel project, I am simply using Laravel Mix in a standalone app)
Step 4 - Registering the Service Worker
There are various ways to do this; some like to inject inline JS into the HTML template, but others, myself included, simply register the service worker at the top of their app.js. Either way, the code should look something along the lines of:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}
Step 5 - Writing your Service Worker; workbox Global, or Module Importing
As mentioned in the previous quote from the documentation, it is encouraged to import the specifically required modules into your service worker, instead of utilising the workbox global or workbox-sw module.
For more information on how to use the individual modules, and how to actually write your service worker, see the following documentation:
https://developers.google.com/web/tools/workbox/guides/using-bundlers
Conclusion
Based on all of my research (which is still ongoing), I have taken the following approach outlined below.
Before reading, please bear in mind that this is configured for a standalone static PWA (i.e. not a full Laravel project).
/src/service-worker.js (the service worker)
When using a bundler such as webpack, it is advised to utlilise import to ensure you include only the necessary workbox modules. This is my service worker skeleton:
import config from '~/config'; // This is where I store project based configurations
import { setCacheNameDetails } from 'workbox-core';
import { precacheAndRoute } from 'workbox-precaching';
import { registerNavigationRoute } from 'workbox-routing';
// Set the cache details
setCacheNameDetails({
prefix: config.app.name.replace(/\s+/g, '-').toLowerCase(),
suffix: config.app.version,
precache: 'precache',
runtime: 'runtime',
googleAnalytics: 'ga'
});
// Load the assets to be precached
precacheAndRoute(self.__precacheManifest);
// Ensure all requests are routed to index.html (SPA)
registerNavigationRoute('/index.html');
/package.json
Splitting the Mix configuration
"scripts": {
"development": "npm run dev-service-worker && npm run dev-core",
"dev": "npm run development",
"dev-service-worker": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js --env.mixfile=service-worker.mix",
"dev-core": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js --env.mixfile=core.mix",
"watch": "npm run dev-core -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"production": "npm run prod-service-worker && npm run prod-core",
"prod": "npm run production",
"prod-service-worker": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js --env.mixfile=service-worker.mix",
"prod-core": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js --env.mixfile=core.mix"
}
Command Explanation
All standard commands will work in the same way as usual (i.e. npm run dev etc.). See known issue about npm run watch
npm run <environment>-service-worker will build just the service worker in the specified environment
npm run <environment>-core will build just the core application in the specified environment
Known Issues
If you are using an html template that utilises the webpack manifest then you may have issues with npm run watch. I have been unable to get this to work correctly as of yet
Downgrading to Laravel Mix 3
"devDependencies": {
"laravel-mix": "^3.0.0"
}
This can also be achieved by running npm install laravel-mix#3.0.0
/static/index.ejs
This HTML template is used to generate the single page application index.html. This template is dependant on the webpack manifest being injected.
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" class="no-js">
<head>
<!-- General meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="<%= config.meta.description %>">
<meta name="rating" content="General">
<meta name="author" content="Sine Macula">
<meta name="robots" content="index, follow">
<meta name="format-detection" content="telephone=no">
<!-- Preconnect and prefetch urls -->
<link rel="preconnect" href="<%= config.api.url %>" crossorigin>
<link rel="dns-prefetch" href="<%= config.api.url %>">
<!-- Theme Colour -->
<meta name="theme-color" content="<%= config.meta.theme %>">
<!-- General link tags -->
<link rel="canonical" href="<%= config.app.url %>">
<!-- Manifest JSON -->
<link rel="manifest" href="<%= StaticAsset('/manifest.json') %>" crossorigin>
<!-- ----------------------------------------------------------------------
---- Icon Tags
---- ----------------------------------------------------------------------
----
---- The following will set up the favicons and the apple touch icons to be
---- used when adding the app to the homescreen of an iPhone, and to
---- display in the head of the browser.
----
---->
<!--[if IE]>
<link rel="shortcut icon" href="<%= StaticAsset('/favicon.ico') %>">
<![endif]-->
<link rel="apple-touch-icon" sizes="72x72" href="<%= StaticAsset('/apple-touch-icon-72x72.png') %>">
<link rel="apple-touch-icon" sizes="120x120" href="<%= StaticAsset('/apple-touch-icon-120x120.png') %>">
<link rel="apple-touch-icon" sizes="180x180" href="<%= StaticAsset('/apple-touch-icon-180x180.png') %>">
<link rel="icon" type="image/png" sizes="16x16" href="<%= StaticAsset('/favicon-16x16.png') %>">
<link rel="icon" type="image/png" sizes="32x32" href="<%= StaticAsset('/favicon-32x32.png') %>">
<link rel="icon" type="image/png" sizes="192x192" href="<%= StaticAsset('/android-chrome-192x192.png') %>">
<link rel="icon" type="image/png" sizes="194x194" href="<%= StaticAsset('/favicon-194x194.png') %>">
<link rel="mask-icon" href="<%= StaticAsset('/safari-pinned-tab.svg') %>" color="<%= config.meta.theme %>">
<meta name="msapplication-TileImage" content="<%= StaticAsset('/mstile-144x144.png') %>">
<meta name="msapplication-TileColor" content="<%= config.meta.theme %>">
<!-- ----------------------------------------------------------------------
---- Launch Images
---- ----------------------------------------------------------------------
----
---- Define the launch 'splash' screen images to be used on iOS.
----
---->
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-640x1136.png') %>" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-750x1294.png') %>" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-1242x2148.png') %>" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-1125x2436.png') %>" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-1536x2048.png') %>" media="(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-1668x2224.png') %>" media="(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="<%= StaticAsset('/assets/images/misc/splash-2048x2732.png') %>" media="(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<!-- ----------------------------------------------------------------------
---- Application Tags
---- ----------------------------------------------------------------------
----
---- Define the application specific tags.
----
---->
<meta name="application-name" content="<%= config.app.name %>">
<meta name="apple-mobile-web-app-title" content="<%= config.app.name %>">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="<%= config.app.status_bar %>">
<meta name="mobile-web-app-capable" content="yes">
<meta name="full-screen" content="yes">
<meta name="browsermode" content="application">
<!-- ----------------------------------------------------------------------
---- Social Media and Open Graph Tags
---- ----------------------------------------------------------------------
----
---- The following will create objects for social media sites to read when
---- scraping the site.
----
---->
<!-- Open Graph -->
<meta property="og:site_name" content="<%= config.app.name %>">
<meta property="og:url" content="<%= config.app.url %>">
<meta property="og:type" content="website">
<meta property="og:title" content="<%= config.meta.title %>">
<meta property="og:description" content="<%= config.meta.description %>">
<meta property="og:image" content="<%= StaticAsset('/assets/images/brand/social-1200x630.jpg') %>">
<!-- Twitter -->
<meta name="twitter:card" content="app">
<meta name="twitter:site" content="<%= config.app.name %>">
<meta name="twitter:title" content="<%= config.meta.title %>">
<meta name="twitter:description" content="<%= config.meta.description %>">
<meta name="twitter:image" content="<%= StaticAsset('/assets/images/brand/social-440x220.jpg') %>">
<!-- ----------------------------------------------------------------------
---- JSON Linked Data
---- ----------------------------------------------------------------------
----
---- This will link the website to its associated social media page. This
---- adds to the credibility of the website as it allows search engines to
---- determine the following of the company via social media
----
---->
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "Organization",
"name": "<%= config.company.name %>",
"url": "<%= config.app.url %>",
"sameAs": [<%= '"' + Object.values(config.company.social).map(x => x.url).join('","') + '"' %>]
}
</script>
<!-- Define the page title -->
<title><%= config.meta.title %></title>
<!-- Generate the prefetch/preload links -->
<% webpack.chunks.slice().reverse().forEach(chunk => { %>
<% chunk.files.forEach(file => { %>
<% if (file.match(/\.(js|css)$/)) { %>
<link rel="<%= chunk.initial ? 'preload' : 'prefetch' %>" href="<%= StaticAsset(file) %>" as="<%= file.match(/\.css$/) ? 'style' : 'script' %>">
<% } %>
<% }) %>
<% }) %>
<!-- Include the core styles -->
<% webpack.chunks.forEach(chunk => { %>
<% chunk.files.forEach(file => { %>
<% if (file.match(/\.(css)$/) && chunk.initial) { %>
<link rel="stylesheet" href="<%= StaticAsset(file) %>">
<% } %>
<% }) %>
<% }) %>
</head>
<body ontouchstart="">
<!-- No javascript error -->
<noscript>JavaScript turned off...</noscript>
<!-- The Vue JS app element -->
<div id="app"></div>
<!-- Include the core scripts -->
<% webpack.chunks.slice().reverse().forEach(chunk => { %>
<% chunk.files.forEach(file => { %>
<% if (file.match(/\.(js)$/) && chunk.initial) { %>
<script type="text/javascript" src="<%= StaticAsset(file) %>"></script>
<% } %>
<% }) %>
<% }) %>
</body>
</html>
/service-worker.mix.js (building the service worker)
This mix configuration will build your Service Worker (service-worker.js), and place it into the root of /dist.
Note: I like to clean my dist folder each time I build my project, and as this functionality must be run at this stage of the build process, I have included it in the below configuration.
const mix = require('laravel-mix');
const path = require('path');
// Set the public path
mix.setPublicPath('dist/');
// Define all the javascript files to be compiled
mix.js('src/js/service-worker.js', 'dist');
// Load any plugins required to compile the files
const Dotenv = require('dotenv-webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// Define the required plugins for webpack
const plugins = [
// Grant access to the environment variables
new Dotenv,
// Ensure the dist folder is cleaned for each build
new CleanWebpackPlugin
];
// Extend the default Laravel Mix webpack configuration
mix.webpackConfig({
plugins,
resolve: {
alias: {
'~': path.resolve('')
}
}
});
// Disable mix-manifest.json (remove this for Laravel projects)
Mix.manifest.refresh = () => void 0;
/core.mix.js (building the application)
This mix configuration will build your main application and place it in /dist/js.
There are various key parts of this mix configuration, each of which has been clearly outlined in the comments within. These are the top-level areas:
Code splitting to app.js, manifest.js, and vendor.js (and dynamic importing)
Laravel Mix versioning does not work as needed for the HTML template so laravel-mix-versionhash is utilised instead
html-webpack-plugin is utilised to generate index.html based on the index.ejs template (see above)
webpack-pwa-manifest is utilised to generate a manifest based
copy-webpack-plugin is utilised to copy the static files to the /dist directory, and to copy any necessary icons to the site root
imagemin-webpack-plugin is used to compress any static images in production
workbox-webpack-plugin is used to inject the webpack manifest into the precaching array used in the service worker. InjectManifest is used, not GenerateSW
Any necessary manifest transformations are applied once the build process is complete
There may be additions to the above but pretty much everything is described by the comments in the following code:
const config = require('./config'); // This is where I store project based configurations
const mix = require('laravel-mix');
const path = require('path');
const fs = require('fs');
// Include any laravel mix plugins
// NOTE: not needed in Laravel projects
require('laravel-mix-versionhash');
// Set the public path
mix.setPublicPath('dist/');
// Define all the SASS files to be compiled
mix.sass('src/sass/app.scss', 'dist/css');
// Define all the javascript files to be compiled
mix.js('src/js/app.js', 'dist/js');
// Split the js into bundles
mix.extract([
// Define the libraries to extract to `vendor`
// e.g. 'vue'
]);
// Ensure the files are versioned when running in production
// NOTE: This is not needed in Laravel projects, you simply need
// run `mix.version`
if (mix.inProduction()) {
mix.versionHash({
length: 8
});
}
// Set any necessary mix options
mix.options({
// This doesn't do anything yet, but once the new version
// of Laravel Mix is released, this 'should' extract the
// styles from the Vue components and place them in a
// css file, as opposed to placing them inline
//extractVueStyles: true,
// Ensure the urls are not processed
processCssUrls: false,
// Apply any postcss plugins
postCss: [
require('css-declaration-sorter'),
require('autoprefixer')
]
});
// Disable mix-manifest.json
// NOTE: not needed in Laravel projects
Mix.manifest.refresh = () => void 0;
// Load any plugins required to compile the files
const Dotenv = require('dotenv-webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackPwaManifest = require('webpack-pwa-manifest');
const { InjectManifest } = require('workbox-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
// Define the required plugins for webpack
const plugins = [
// Grant access to the environment variables
new Dotenv,
// Process and build the html template
// NOTE: not needed if using Laravel and blade
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'static', 'index.ejs'),
inject: false,
minify: !mix.inProduction() ? false : {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
useShortDoctype: true
},
templateParameters: compilation => ({
webpack: compilation.getStats().toJson(),
config,
StaticAsset: (file) => {
// This will ensure there are no double slashes (bug in Laravel Mix)
return (config.app.static_url + '/' + file).replace(/([^:]\/)\/+/g, "$1");
}
})
}),
// Generate the manifest file
new WebpackPwaManifest({
publicPath: '',
filename: 'manifest.json',
name: config.app.name,
description: config.meta.description,
theme_color: config.meta.theme,
background_color: config.meta.theme,
orientation: config.app.orientation,
display: "fullscreen",
start_url: '/',
inject: false,
fingerprints: false,
related_applications: [
{
platform: 'play',
url: config.app.stores.google.url,
id: config.app.stores.google.id
},
{
platform: 'itunes',
url: config.app.stores.apple.url,
id: config.app.stores.apple.id
}
],
// TODO: Update this once the application is live
screenshots: [
{
src: config.app.static_url + '/assets/images/misc/screenshot-1-720x1280.png',
sizes: '1280x720',
type: 'image/png'
}
],
icons: [
{
src: path.resolve(__dirname, 'static/assets/images/icons/android-chrome-512x512.png'),
sizes: [72, 96, 128, 144, 152, 192, 384, 512],
destination: path.join('assets', 'images', 'icons')
}
]
}),
// Copy any necessary directories/files
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, 'static'),
to: path.resolve(__dirname, 'dist'),
toType: 'dir',
ignore: ['*.ejs']
},
{
from: path.resolve(__dirname, 'static/assets/images/icons'),
to: path.resolve(__dirname, 'dist'),
toType: 'dir'
}
]),
// Ensure any images are optimised when copied
new ImageminPlugin({
disable: process.env.NODE_ENV !== 'production',
test: /\.(jpe?g|png|gif|svg)$/i
}),
new InjectManifest({
swSrc: path.resolve('dist/service-worker.js'),
importWorkboxFrom: 'disabled',
importsDirectory: 'js'
})
];
// Extend the default Laravel Mix webpack configuration
mix.webpackConfig({
plugins,
output: {
chunkFilename: 'js/[name].js',
}
}).then(() => {
// As the precached filename is hashed, we need to read the
// directory in order to find the filename. Assuming there
// are no other files called `precache-manifest`, we can assume
// it is the first value in the filtered array. There is no
// need to test if [0] has a value because if it doesn't
// this needs to throw an error
let filename = fs
.readdirSync(path.normalize(`${__dirname}/dist/js`))
.filter(filename => filename.startsWith('precache-manifest'))[0];
// In order to load the precache manifest file, we need to define
// self in the global as it is not available in node.
global['self'] = {};
require('./dist/js/' + filename);
let manifest = self.__precacheManifest;
// Loop through the precache manifest and apply any transformations
manifest.map(entry => {
// Remove any double slashes
entry.url = entry.url.replace(/(\/)\/+/g, "$1");
// If the filename is hashed then remove the revision
if (entry.url.match(/\.[0-9a-f]{8}\./)) {
delete entry.revision;
}
// Apply any other transformations or additions here...
});
// Filter out any entries that should not be in the manifest
manifest = manifest.filter(entry => {
return entry.url.match(/.*\.(css|js|html|json)$/)
|| entry.url.match(/^\/([^\/]+\.(png|ico|svg))$/)
|| entry.url.match(/\/images\/icons\/icon_([^\/]+\.(png))$/)
|| entry.url.match(/\/images\/misc\/splash-([^\/]+\.(png))$/);
});
// Concatenate the contents of the precache manifest and then save
// the file
const content = 'self.__precacheManifest = (self.__precacheManifest || []).concat(' + JSON.stringify(manifest) + ');';
fs.writeFileSync('./dist/js/' + filename, content, 'utf8', () => {});
});
/src/js/app.js (the main application)
This is where you register your service worker, and obviously define your application etc...
/**
* Register the service worker as soon as the page has finished loading.
*/
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
// TODO: Broadcast updates of the service worker here...
navigator.serviceWorker.register('/service-worker.js');
});
}
// Define the rest of your application here...
// e.g. window.Vue = require('vue');
I am just starting out with Vue and am trying to use two components in a route - a navbar and some sales data. Laravel mix is bundling the assets with Webpack, and npm keeps failing.
index.php
<body>
<div id="app">
<router-view name="nav"></router-view>
<router-view></router-view>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
app.js:
import './bootstrap';
import router from './routes';
const app = new Vue({
el: '#app',
router
});
routes.js:
import VueRouter from 'vue-router';
import Sales from './views/employer/sales/Sales.vue';
import MainNav from './components/MainNav.vue';
let routes = [
{
path: '/sales',
components: {
default: Sales,
nav: MainNav
}
}
];
export default new VueRouter({
routes,
linkActiveClass: 'is-active'
});
Sales.vue
<template>
<p>This is the Sales view</p>
</template>
MainNav.vue
<template>
<p>This is the MAIN NAVIGATION</p>
</template>
The error message from npm is not particularly enlightening:
Failed at the # dev script 'node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
It goes on to suggest that I should check I am running the latest node and npm (which I am).
What am I doing wrong? Curiously, before attempting to include the navigation component this way, I was registering it as a global component. It seemed to register fine, but whenever I included its element tag in a template, npm would fail in the same manner as above.
Looks like node somehow became confused. I removed the node_modules directory and reinstalled it and its all good.