如何使用Laravel Mix和WorkBox? [英] How to use Laravel Mix and WorkBox?

查看:185
本文介绍了如何使用Laravel Mix和WorkBox?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的应用构建PWA;并且花了近48个小时试图弄清楚如何将Workbox与Laravel Mix结合使用.具有讽刺意味的是,Google表示Workbox旨在使事情变得简单!

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 -

  1. 我需要使用InjectManifest Plugin,因为我想在我的Service Worker中集成推送通知服务

  1. I will need to use the InjectManifest Plugin because I want to integrate Push notifications service in my Service Worker

我不知道如何指定swSrcswDest的路径.

I have no clue how to specifiy the paths for swSrc and swDest.

什么代码应该放入我的webpack.mix.js中,以及是否应该在我的resources/js文件夹中包含一个临时服务工作者,以便在public/文件夹中创建一个新的服务工作者.

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.

有人可以帮忙吗?

PS:我几乎阅读了所有博客和帮助文章;但是没有人谈论将Workbox与Laravel mix可靠地结合使用.非常感谢您的帮助.

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.

出于这个答案的目的,我假设您的服务人员称为service-worker.js,但是,您显然可以随便调用它.

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.

假设您使用的是在项目中进行动态导入(如果不是),则需要将Laravel Mix降级到版本3.有一个

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.

此外,此答案中概述的步骤是专门为Laravel Mix 3配置的.

In addition, the steps outlined in this answer are specifically configured for Laravel Mix 3.

要解决的第二个问题是是使用workbox-webpack-plugin来使用importScripts注入workbox全局变量,还是应该禁用此功能(使用importWorkboxFrom: 'disabled'),而只是单独导入所需的特定模块.

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...

文档指出:

使用JavaScript捆绑器时,您不需要(实际上也不应该使用)workbox全局模块或workbox-sw模块,因为您可以直接导入各个软件包文件.

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.

这意味着我们应该使用import而不是注入importScripts.

This implies that we should be using import instead of injecting the importScripts.

但是,这里有很多问题:

However, there are various issues here:

  • 我们不希望将service-worker.js包含在构建清单中,因为它将被注入到预缓存清单中.
  • 我们不希望在production中对service-worker.js进行版本控制,即名称应始终为service-worker.js,而不是service-worker.123abc.js.
  • InjectManifest将无法插入清单,因为service-worker.js文件在运行时将不存在.
  • 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.

因此,为了利用import代替importScripts,我们必须具有两个单独的Webpack(混合)配置(有关如何执行此操作的指南,请参见结论).我不是100%肯定这是正确的,但是一旦收到以下任一答案,我将更新我的答案(请支持他们,以增加获得答案的机会):

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

假设您使用的是InjectManifest而不是GenerateSW,则需要编写自己的服务人员,该服务人员将在每个构建中的webpack插件中注入JS清单.简而言之,这意味着您需要在源目录中创建一个文件,以用作服务工作程序.

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.

矿井位于src/js/service-worker.js(如果您在一个完整的Laravel项目中进行构建,这会有所不同,我只是在独立应用程序中使用Laravel Mix)

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)

有多种方法可以做到这一点;有些人喜欢将内联JS注入HTML模板,而其他人(包括我自己)只需在app.js顶部注册服务工作者即可.无论哪种方式,代码都应遵循以下内容:

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');
    });
}

第5步-编写服务工作者; workbox全局或模块导入

如文档前面的引文中所述,建议将特殊需要的模块导入服务工作者,而不要使用workbox全局或workbox-sw模块.

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

基于我的所有研究(仍在进行中),我采用了以下概述的方法.

Based on all of my research (which is still ongoing), I have taken the following approach outlined below.

在阅读之前,请记住,它是为独立的静态PWA(即不是完整的Laravel项目)配置的.

Before reading, please bear in mind that this is configured for a standalone static PWA (i.e. not a full Laravel project).

在使用诸如webpack之类的捆绑器时,建议使用import以确保仅包括必要的workbox模块.这是我的服务人员骨架:

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

拆分Mix配置

/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"  
}

命令说明

  • 所有标准命令将以与通常相同的方式工作(即npm run dev等).请参阅有关npm run watch
  • 的已知问题
  • npm run <environment>-service-worker将仅在指定环境中构建服务工作者
  • npm run <environment>-core将仅在指定环境中构建核心应用程序
  • 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

已知问题

  • 如果您使用的HTML模板利用了webpack清单,则npm run watch可能会出现问题.到目前为止,我还无法使它正常工作
  • 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
"devDependencies": {  
    "laravel-mix": "^3.0.0"  
}

这也可以通过运行npm install laravel-mix@3.0.0

此HTML模板用于生成单页应用程序index.html.该模板取决于要注入的webpack清单.

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(构建服务工作者)

此混合配置将构建您的Service Worker(service-worker.js),并将其放置在的根目录中.

/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.

注意::我每次构建项目时都希望清理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(构建应用程序)

此混合配置将构建您的主应用程序并将其放置在中.

/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:

  • 将代码拆分为app.jsmanifest.jsvendor.js(以及动态导入)
  • Laravel Mix版本控制无法按HTML模板的要求运行,因此可以使用laravel-mix-versionhash代替
  • html-webpack-plugin用于基于index.ejs模板(参见上文)生成index.html
  • webpack-pwa-manifest用于生成基于清单的
  • copy-webpack-plugin用于将静态文件复制到/dist目录,并将所有必要的图标复制到站点根目录
  • imagemin-webpack-plugin用于压缩production
  • 中的任何静态图像
  • workbox-webpack-plugin用于将Webpack清单注入到服务工作器中使用的预缓存阵列中.使用InjectManifest,而不使用GenerateSW
  • 构建过程完成后,将应用所有必要的清单转换
  • 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(主要应用程序)

在这里您可以注册服务工作者,并明确定义您的应用程序等.

/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');

这篇关于如何使用Laravel Mix和WorkBox?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆