mirror of
https://github.com/a2nt/silverstripe-progressivewebapp.git
synced 2024-10-22 11:05:45 +02:00
Compare commits
No commits in common. "master" and "v1.1" have entirely different histories.
@ -1,8 +1,6 @@
|
|||||||
# For more information about the properties used in
|
# For more information about the properties used in this file,
|
||||||
# this file, please see the EditorConfig documentation:
|
# please see the EditorConfig documentation:
|
||||||
# http://editorconfig.org/
|
# http://editorconfig.org
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
@ -12,15 +10,8 @@ indent_style = space
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.md]
|
[{*.yml,package.json,*.scss,*.js}]
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
||||||
[*.yml]
|
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
|
||||||
|
|
||||||
[{.travis.yml,package.json}]
|
# The indent size used in the package.json file cannot be changed:
|
||||||
# The indent size used in the `package.json` file cannot be changed
|
|
||||||
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
/client/src/thirdparty
|
|
262
.eslintrc
262
.eslintrc
@ -1,262 +0,0 @@
|
|||||||
{
|
|
||||||
// http://eslint.org/docs/rules/
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
|
|
||||||
"settings": {
|
|
||||||
"react": {
|
|
||||||
"version": "detect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"env": {
|
|
||||||
"browser": true, // browser global variables.
|
|
||||||
"node": true, // Node.js global variables and Node.js-specific rules.
|
|
||||||
"amd": true, // defines require() and define() as global variables as per the amd spec.
|
|
||||||
"mocha": false, // adds all of the Mocha testing global variables.
|
|
||||||
"jasmine": false, // adds all of the Jasmine testing global variables for version 1.3 and 2.0.
|
|
||||||
"phantomjs": false, // phantomjs global variables.
|
|
||||||
"jquery": true, // jquery global variables.
|
|
||||||
"prototypejs": false, // prototypejs global variables.
|
|
||||||
"shelljs": false, // shelljs global variables.
|
|
||||||
"es6": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"globals": {
|
|
||||||
// e.g. "angular": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"plugins": [
|
|
||||||
"react",
|
|
||||||
"import",
|
|
||||||
"jquery"
|
|
||||||
],
|
|
||||||
|
|
||||||
"parser": "babel-eslint",
|
|
||||||
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 6,
|
|
||||||
"sourceType": "module",
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true,
|
|
||||||
"experimentalObjectRestSpread": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"rules": {
|
|
||||||
////////// Possible Errors //////////
|
|
||||||
|
|
||||||
"no-comma-dangle": 0, // disallow trailing commas in object literals
|
|
||||||
"no-cond-assign": 0, // disallow assignment in conditional expressions
|
|
||||||
"no-console": 0, // disallow use of console (off by default in the node environment)
|
|
||||||
"no-constant-condition": 0, // disallow use of constant expressions in conditions
|
|
||||||
"no-control-regex": 0, // disallow control characters in regular expressions
|
|
||||||
"no-debugger": 0, // disallow use of debugger
|
|
||||||
"no-dupe-keys": 0, // disallow duplicate keys when creating object literals
|
|
||||||
"no-empty": 0, // disallow empty statements
|
|
||||||
"no-empty-class": 0, // disallow the use of empty character classes in regular expressions
|
|
||||||
"no-ex-assign": 0, // disallow assigning to the exception in a catch block
|
|
||||||
"no-extra-boolean-cast": 0, // disallow double-negation boolean casts in a boolean context
|
|
||||||
"no-extra-parens": 0, // disallow unnecessary parentheses (off by default)
|
|
||||||
"no-extra-semi": 0, // disallow unnecessary semicolons
|
|
||||||
"no-func-assign": 0, // disallow overwriting functions written as function declarations
|
|
||||||
"no-inner-declarations": 0, // disallow function or variable declarations in nested blocks
|
|
||||||
"no-invalid-regexp": 0, // disallow invalid regular expression strings in the RegExp constructor
|
|
||||||
"no-irregular-whitespace": 0, // disallow irregular whitespace outside of strings and comments
|
|
||||||
"no-negated-in-lhs": 0, // disallow negation of the left operand of an in expression
|
|
||||||
"no-obj-calls": 0, // disallow the use of object properties of the global object (Math and JSON) as functions
|
|
||||||
"no-regex-spaces": 0, // disallow multiple spaces in a regular expression literal
|
|
||||||
"no-reserved-keys": 0, // disallow reserved words being used as object literal keys (off by default)
|
|
||||||
"no-sparse-arrays": 0, // disallow sparse arrays
|
|
||||||
"no-unreachable": 0, // disallow unreachable statements after a return, throw, continue, or break statement
|
|
||||||
"use-isnan": 0, // disallow comparisons with the value NaN
|
|
||||||
"valid-jsdoc": 0, // Ensure JSDoc comments are valid (off by default)
|
|
||||||
"valid-typeof": 0, // Ensure that the results of typeof are compared against a valid string
|
|
||||||
|
|
||||||
|
|
||||||
////////// Best Practices //////////
|
|
||||||
|
|
||||||
"block-scoped-var": 0, // treat var statements as if they were block scoped (off by default)
|
|
||||||
"complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default)
|
|
||||||
"consistent-return": 0, // require return statements to either always or never specify values
|
|
||||||
"curly": 0, // specify curly brace conventions for all control statements
|
|
||||||
"default-case": 0, // require default case in switch statements (off by default)
|
|
||||||
"dot-notation": 0, // encourages use of dot notation whenever possible
|
|
||||||
"eqeqeq": 0, // require the use of === and !==
|
|
||||||
"guard-for-in": 0, // make sure for-in loops have an if statement (off by default)
|
|
||||||
"no-alert": 0, // disallow the use of alert, confirm, and prompt
|
|
||||||
"no-caller": 0, // disallow use of arguments.caller or arguments.callee
|
|
||||||
"no-div-regex": 0, // disallow division operators explicitly at beginning of regular expression (off by default)
|
|
||||||
"no-else-return": 0, // disallow else after a return in an if (off by default)
|
|
||||||
"no-empty-label": 0, // disallow use of labels for anything other then loops and switches
|
|
||||||
"no-eq-null": 0, // disallow comparisons to null without a type-checking operator (off by default)
|
|
||||||
"no-eval": 0, // disallow use of eval()
|
|
||||||
"no-extend-native": 0, // disallow adding to native types
|
|
||||||
"no-extra-bind": 0, // disallow unnecessary function binding
|
|
||||||
"no-fallthrough": 0, // disallow fallthrough of case statements
|
|
||||||
"no-floating-decimal": 0, // disallow the use of leading or trailing decimal points in numeric literals (off by default)
|
|
||||||
"no-implied-eval": 0, // disallow use of eval()-like methods
|
|
||||||
"no-iterator": 0, // disallow usage of __iterator__ property
|
|
||||||
"no-labels": 0, // disallow use of labeled statements
|
|
||||||
"no-lone-blocks": 0, // disallow unnecessary nested blocks
|
|
||||||
"no-loop-func": 0, // disallow creation of functions within loops
|
|
||||||
"no-multi-spaces": 0, // disallow use of multiple spaces
|
|
||||||
"no-multi-str": 0, // disallow use of multiline strings
|
|
||||||
"no-native-reassign": 0, // disallow reassignments of native objects
|
|
||||||
"no-new": 0, // disallow use of new operator when not part of the assignment or comparison
|
|
||||||
"no-new-func": 0, // disallow use of new operator for Function object
|
|
||||||
"no-new-wrappers": 0, // disallows creating new instances of String, Number, and Boolean
|
|
||||||
"no-octal": 0, // disallow use of octal literals
|
|
||||||
"no-octal-escape": 0, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251";
|
|
||||||
"no-process-env": 0, // disallow use of process.env (off by default)
|
|
||||||
"no-proto": 0, // disallow usage of __proto__ property
|
|
||||||
"no-redeclare": 0, // disallow declaring the same variable more then once
|
|
||||||
"no-return-assign": 0, // disallow use of assignment in return statement
|
|
||||||
"no-script-url": 0, // disallow use of javascript: urls.
|
|
||||||
"no-self-compare": 0, // disallow comparisons where both sides are exactly the same (off by default)
|
|
||||||
"no-sequences": 0, // disallow use of comma operator
|
|
||||||
"no-unused-expressions": 0, // disallow usage of expressions in statement position
|
|
||||||
"no-void": 0, // disallow use of void operator (off by default)
|
|
||||||
"no-warning-comments": 0, // disallow usage of configurable warning terms in comments, e.g. TODO or FIXME (off by default)
|
|
||||||
"no-with": 0, // disallow use of the with statement
|
|
||||||
"radix": 0, // require use of the second argument for parseInt() (off by default)
|
|
||||||
"vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default)
|
|
||||||
"wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default)
|
|
||||||
"yoda": 0, // require or disallow Yoda conditions
|
|
||||||
|
|
||||||
|
|
||||||
////////// Strict Mode //////////
|
|
||||||
|
|
||||||
"global-strict": 0, // (deprecated) require or disallow the "use strict" pragma in the global scope (off by default in the node environment)
|
|
||||||
"no-extra-strict": 0, // (deprecated) disallow unnecessary use of "use strict"; when already in strict mode
|
|
||||||
"strict": 0, // controls location of Use Strict Directives
|
|
||||||
|
|
||||||
|
|
||||||
////////// Variables //////////
|
|
||||||
|
|
||||||
"no-catch-shadow": 0, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment)
|
|
||||||
"no-delete-var": 0, // disallow deletion of variables
|
|
||||||
"no-label-var": 0, // disallow labels that share a name with a variable
|
|
||||||
"no-shadow": 0, // disallow declaration of variables already declared in the outer scope
|
|
||||||
"no-shadow-restricted-names": 0, // disallow shadowing of names such as arguments
|
|
||||||
"no-undef": 0, // disallow use of undeclared variables unless mentioned in a /*global */ block
|
|
||||||
"no-undef-init": 0, // disallow use of undefined when initializing variables
|
|
||||||
"no-undefined": 0, // disallow use of undefined variable (off by default)
|
|
||||||
"no-unused-vars": 0, // disallow declaration of variables that are not used in the code
|
|
||||||
"no-use-before-define": 0, // disallow use of variables before they are defined
|
|
||||||
|
|
||||||
|
|
||||||
////////// Node.js //////////
|
|
||||||
|
|
||||||
"handle-callback-err": 0, // enforces error handling in callbacks (off by default) (on by default in the node environment)
|
|
||||||
"no-mixed-requires": 0, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment)
|
|
||||||
"no-new-require": 0, // disallow use of new operator with the require function (off by default) (on by default in the node environment)
|
|
||||||
"no-path-concat": 0, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment)
|
|
||||||
"no-process-exit": 0, // disallow process.exit() (on by default in the node environment)
|
|
||||||
"no-restricted-modules": 0, // restrict usage of specified node modules (off by default)
|
|
||||||
"no-sync": 0, // disallow use of synchronous methods (off by default)
|
|
||||||
|
|
||||||
|
|
||||||
////////// Stylistic Issues //////////
|
|
||||||
|
|
||||||
"brace-style": 0, // enforce one true brace style (off by default)
|
|
||||||
"camelcase": 0, // require camel case names
|
|
||||||
"comma-spacing": 0, // enforce spacing before and after comma
|
|
||||||
"comma-style": 0, // enforce one true comma style (off by default)
|
|
||||||
"consistent-this": 0, // enforces consistent naming when capturing the current execution context (off by default)
|
|
||||||
"eol-last": 0, // enforce newline at the end of file, with no multiple empty lines
|
|
||||||
"func-names": 0, // require function expressions to have a name (off by default)
|
|
||||||
"func-style": 0, // enforces use of function declarations or expressions (off by default)
|
|
||||||
"key-spacing": 0, // enforces spacing between keys and values in object literal properties
|
|
||||||
"max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested (off by default)
|
|
||||||
"new-cap": 0, // require a capital letter for constructors
|
|
||||||
"new-parens": 0, // disallow the omission of parentheses when invoking a constructor with no arguments
|
|
||||||
"no-array-constructor": 0, // disallow use of the Array constructor
|
|
||||||
"no-inline-comments": 0, // disallow comments inline after code (off by default)
|
|
||||||
"no-lonely-if": 0, // disallow if as the only statement in an else block (off by default)
|
|
||||||
"no-mixed-spaces-and-tabs": 0, // disallow mixed spaces and tabs for indentation
|
|
||||||
"no-multiple-empty-lines": 0, // disallow multiple empty lines (off by default)
|
|
||||||
"no-nested-ternary": 0, // disallow nested ternary expressions (off by default)
|
|
||||||
"no-new-object": 0, // disallow use of the Object constructor
|
|
||||||
"no-space-before-semi": 0, // disallow space before semicolon
|
|
||||||
"no-spaced-func": 0, // disallow space between function identifier and application
|
|
||||||
"no-ternary": 0, // disallow the use of ternary operators (off by default)
|
|
||||||
"no-trailing-spaces": 0, // disallow trailing whitespace at the end of lines
|
|
||||||
"no-underscore-dangle": 0, // disallow dangling underscores in identifiers
|
|
||||||
"no-wrap-func": 0, // disallow wrapping of non-IIFE statements in parens
|
|
||||||
"one-var": 0, // allow just one var statement per function (off by default)
|
|
||||||
"operator-assignment": 0, // require assignment operator shorthand where possible or prohibit it entirely (off by default)
|
|
||||||
"padded-blocks": 0, // enforce padding within blocks (off by default)
|
|
||||||
"quote-props": 0, // require quotes around object literal property names (off by default)
|
|
||||||
"quotes": 0, // specify whether double or single quotes should be used
|
|
||||||
"semi": 0, // require or disallow use of semicolons instead of ASI
|
|
||||||
"sort-vars": 0, // sort variables within the same declaration block (off by default)
|
|
||||||
"space-after-function-name": 0, // require a space after function names (off by default)
|
|
||||||
"space-after-keywords": 0, // require a space after certain keywords (off by default)
|
|
||||||
"space-before-blocks": 0, // require or disallow space before blocks (off by default)
|
|
||||||
"space-in-brackets": 0, // require or disallow spaces inside brackets (off by default)
|
|
||||||
"space-in-parens": 0, // require or disallow spaces inside parentheses (off by default)
|
|
||||||
"space-infix-ops": 0, // require spaces around operators
|
|
||||||
"space-return-throw-case": 0, // require a space after return, throw, and case
|
|
||||||
"space-unary-ops": 0, // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default)
|
|
||||||
"spaced-line-comment": 0, // require or disallow a space immediately following the // in a line comment (off by default)
|
|
||||||
"wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default)
|
|
||||||
|
|
||||||
|
|
||||||
////////// ECMAScript 6 //////////
|
|
||||||
|
|
||||||
"no-var": 0, // require let or const instead of var (off by default)
|
|
||||||
"generator-star": 0, // enforce the position of the * in generator functions (off by default)
|
|
||||||
|
|
||||||
|
|
||||||
////////// Legacy //////////
|
|
||||||
|
|
||||||
"max-depth": 0, // specify the maximum depth that blocks can be nested (off by default)
|
|
||||||
"max-len": 0, // specify the maximum length of a line in your program (off by default)
|
|
||||||
"max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default)
|
|
||||||
"max-statements": 0, // specify the maximum number of statement allowed in a function (off by default)
|
|
||||||
"no-bitwise": 0, // disallow use of bitwise operators (off by default)
|
|
||||||
"no-plusplus": 0, // disallow use of unary operators, ++ and -- (off by default)
|
|
||||||
|
|
||||||
//////// Extra //////////
|
|
||||||
"array-bracket-spacing": ["error", "never"],
|
|
||||||
"array-callback-return": "error",
|
|
||||||
"arrow-parens": ["error", "always"],
|
|
||||||
"arrow-spacing": ["error", { "before": true, "after": true }],
|
|
||||||
"comma-dangle": ["error", "always-multiline"],
|
|
||||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
|
||||||
"no-case-declarations": "error",
|
|
||||||
"no-confusing-arrow": "error",
|
|
||||||
"no-duplicate-imports": "error",
|
|
||||||
"no-param-reassign": "error",
|
|
||||||
"no-useless-escape": "error",
|
|
||||||
"object-curly-spacing": ["error", "always"],
|
|
||||||
"object-shorthand": ["error", "properties"],
|
|
||||||
"prefer-arrow-callback": "error",
|
|
||||||
"prefer-const": "error",
|
|
||||||
"prefer-template": "error",
|
|
||||||
"react/jsx-closing-bracket-location": "error",
|
|
||||||
"react/jsx-curly-spacing": ["error", "never", {"allowMultiline": true}],
|
|
||||||
"react/jsx-filename-extension": ["error", { "extensions": [".react.js", ".js", ".jsx"] }],
|
|
||||||
"react/jsx-no-duplicate-props": "error",
|
|
||||||
"react/jsx-no-bind": ["error", { "ignoreRefs": true, "allowArrowFunctions": true, "allowBind": false }],
|
|
||||||
"react/jsx-no-undef": "error",
|
|
||||||
"react/jsx-pascal-case": "error",
|
|
||||||
"react/jsx-tag-spacing": ["error", {"closingSlash": "never", "beforeSelfClosing": "always", "afterOpening": "never"}],
|
|
||||||
"react/jsx-uses-react": "error",
|
|
||||||
"react/jsx-uses-vars": "error",
|
|
||||||
"react/no-danger": "error",
|
|
||||||
"react/no-deprecated": "error",
|
|
||||||
"react/no-did-mount-set-state": "error",
|
|
||||||
"react/no-did-update-set-state": "error",
|
|
||||||
"react/no-direct-mutation-state": "error",
|
|
||||||
"react/no-is-mounted": "error",
|
|
||||||
"react/no-multi-comp": "error",
|
|
||||||
"react/prefer-es6-class": "error",
|
|
||||||
"react/prop-types": "error",
|
|
||||||
"react/require-render-return": "error",
|
|
||||||
"react/self-closing-comp": "error",
|
|
||||||
"react/sort-comp": "error",
|
|
||||||
"import/no-mutable-exports": "error",
|
|
||||||
"import/imports-first": "warn"
|
|
||||||
}
|
|
||||||
}
|
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,3 @@
|
|||||||
/node_modules
|
/node_modules/
|
||||||
/yarn.lock
|
/**/*.js.map
|
||||||
yarn-error\.log
|
/**/*.css.map
|
||||||
|
2
.npmrc
2
.npmrc
@ -1,2 +0,0 @@
|
|||||||
registry=https://npm.pkg.github.com/a2nt
|
|
||||||
registry=https://registry.npmjs.org/
|
|
31
README.md
31
README.md
@ -1,33 +1,16 @@
|
|||||||
# SilverStripe Progressive Web App
|
# SilverStripe Progressive Web App
|
||||||
|
|
||||||
Tools to add progressive web app functionality to your silverstripe website
|
Tools to add progressive web app functionality to your silverstripe website
|
||||||
And make it available offline
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```
|
```
|
||||||
composer require a2nt/silverstripe-progressivewebapp
|
composer require pixelspin/silverstripe-progressivewebapp
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
- Install the module, run dev/build and fill in the settings in the siteconfig
|
Install the module, run dev/build and fill in the settings in the siteconfig
|
||||||
- Add js to register the service worker (example can be found at client/src/app.js)
|
Place the link to the manifest file (<link rel="manifest" href="{$BaseHref}manifest.json">) in the head of your pages and add the color meta data as well (<meta name="theme-color" content="$SiteConfig.ManifestColor">)
|
||||||
```
|
Include the js (Requirements::javascript('pixelspin/silverstripe-progressivewebapp:resources/js/progressivewebapp.js');)
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
var baseHref = (document.getElementsByTagName('base')[0] || {}).href;
|
## Todo
|
||||||
var version = (document.querySelector('meta[name="swversion"]') || {})
|
Improve the documentation
|
||||||
.content;
|
|
||||||
if (baseHref) {
|
|
||||||
navigator.serviceWorker
|
|
||||||
.register(baseHref + 'sw.js?v=' + version)
|
|
||||||
.then(() => {
|
|
||||||
console.log('SW: Registered');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Add the following tags to the head of your website
|
|
||||||
```
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
<link rel="manifest" href="{$BaseHref}manifest.json" />
|
|
||||||
<meta name="swversion" content="{$SWVersion}" />
|
|
||||||
```
|
|
@ -1 +0,0 @@
|
|||||||
<?php
|
|
@ -4,10 +4,8 @@ Name: progressivewebapp
|
|||||||
|
|
||||||
SilverStripe\Control\Director:
|
SilverStripe\Control\Director:
|
||||||
rules:
|
rules:
|
||||||
'manifest.json': 'A2nt\ProgressiveWebApp\Controllers\ManifestController'
|
'manifest.json': 'Pixelspin\ProgressiveWebApp\Controllers\ProgressiveWebAppController'
|
||||||
'sw.js/$Action': 'A2nt\ProgressiveWebApp\Controllers\ServiceWorkerController'
|
|
||||||
'.well-known/$Action!': 'A2nt\ProgressiveWebApp\Controllers\WellKnownController'
|
|
||||||
|
|
||||||
SilverStripe\CMS\Model\SiteTree:
|
SilverStripe\SiteConfig\SiteConfig:
|
||||||
extensions:
|
extensions:
|
||||||
- A2nt\ProgressiveWebApp\Extensions\SiteTree
|
- Pixelspin\ProgressiveWebApp\Extensions\ProgressiveWebAppSiteConfigExtension
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
[
|
|
||||||
"@babel/preset-env",
|
|
||||||
{
|
|
||||||
"targets": {
|
|
||||||
"node": "6.10",
|
|
||||||
"browsers": "> 0.25%, not dead"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@babel/preset-react",
|
|
||||||
{
|
|
||||||
"pragma": "dom", // default pragma is React.createElement (only in classic runtime)
|
|
||||||
"pragmaFrag": "DomFrag", // default is React.Fragment (only in classic runtime)
|
|
||||||
"throwIfNamespace": false, // defaults to true
|
|
||||||
"runtime": "classic" // defaults to classic
|
|
||||||
// "importSource": "custom-jsx-library" // defaults to react (only in automatic runtime)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"@babel/plugin-syntax-top-level-await",
|
|
||||||
"@babel/plugin-proposal-object-rest-spread",
|
|
||||||
"@babel/plugin-syntax-jsx"
|
|
||||||
]
|
|
||||||
}
|
|
1
client/dist/js/app_app.js
vendored
1
client/dist/js/app_app.js
vendored
@ -1 +0,0 @@
|
|||||||
!function(){if("serviceWorker"in navigator){var e=(document.getElementsByTagName("base")[0]||{}).href,n=(document.querySelector('meta[name="swversion"]')||{}).content;e&&navigator.serviceWorker.register("".concat(e,"sw.js?v=").concat(n)).then((function(){console.log("SW: Registered")}))}}();
|
|
1
client/dist/js/app_sw.js
vendored
1
client/dist/js/app_sw.js
vendored
@ -1 +0,0 @@
|
|||||||
!function(){var e={729:function(e){e.exports=function log(e){debug&&console.log(e)}},671:function(e){Cache.prototype.add||(Cache.prototype.add=function add(e){return this.addAll([e])}),Cache.prototype.addAll||(Cache.prototype.addAll=function addAll(e){var t=this;function NetworkError(e){this.name="NetworkError",this.code=19,this.message=e}return NetworkError.prototype=Object.create(Error.prototype),Promise.resolve().then((function(){if(arguments.length<1)throw new TypeError;return e=e.map((function(e){return e instanceof Request?e:String(e)})),Promise.all(e.map((function(e){"string"===typeof e&&(e=new Request(e));var t=new URL(e.url).protocol;if("http:"!==t&&"https:"!==t)throw new NetworkError("Invalid scheme");return fetch(e.clone())})))})).then((function(n){return Promise.all(n.map((function(n,r){return t.put(e[r],n)})))})).then((function(){}))}),CacheStorage.prototype.match||(CacheStorage.prototype.match=function match(e,t){var n=this;return this.keys().then((function(r){var o;return r.reduce((function(r,i){return r.then((function(){return o||n.open(i).then((function(n){return n.match(e,t)})).then((function(e){return o=e}))}))}),Promise.resolve())}))}),e.exports=self.caches}},t={};function __webpack_require__(n){var r=t[n];if(void 0!==r)return r.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,__webpack_require__),o.exports}!function(){var e=__webpack_require__(729),t=__webpack_require__(671);if(debug&&(e("SW: debug is on"),e("SW: CACHE_NAME: ".concat(CACHE_NAME)),e("SW: appDomain: ".concat(appDomain)),e("SW: lang: ".concat(lang))),"string"!==typeof self.CACHE_NAME)throw new Error("Cache Name cannot be empty");self.addEventListener("fetch",(function(n){if("GET"===n.request.method){var r=new URL(n.request.url);if(r.pathname.indexOf("turnstile")>=0&&e("SW: skip captcha ".concat(n.request.url)),r.pathname.indexOf("admin")>=0||r.pathname.indexOf("Security")>=0||r.pathname.indexOf("dev")>=0)e("SW: skip admin ".concat(n.request.url));else{var o=n.request.clone(),i=n.request.clone();n.respondWith(fetch(o).then((function(e){var r=e.clone();return t.open(self.CACHE_NAME).then((function(e){var t=n.request.clone();e.put(t,r)})),e})).catch((function(n){return e("SW: fetch failed"),t.match(i)})))}}})),self.addEventListener("activate",(function(n){e("SW: activated: ".concat(version)),n.waitUntil(t.delete(self.CACHE_NAME))})),self.addEventListener("fetch",(function(e){var n=e.request;e.respondWith(t.match(n).then((function(e){return e||fetch(n).then((function(e){return e})).catch((function(){if(n.url.match(/\.(jpe?g|png|gif|svg)$/))return new Response('<svg role="img" aria-labelledby="offline-title" viewBox="0 0 400 225" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice"><title id="offline-title">Offline</title><path fill="rgba(145,145,145,0.5)" d="M0 0h400v225H0z" /><text fill="rgba(0,0,0,0.33)" font-family="Helvetica Neue,Arial,sans-serif" font-size="27" text-anchor="middle" x="200" y="113" dominant-baseline="central">offline</text></svg>',{headers:{"Content-Type":"image/svg+xml"}})}))})))})),self.addEventListener("install",(function(t){e("SW: installing version: ".concat(version))}))}()}();
|
|
30
client/dist/records.json
vendored
30
client/dist/records.json
vendored
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"chunks": {
|
|
||||||
"byName": {
|
|
||||||
"app_app": 21,
|
|
||||||
"app_sw": 898
|
|
||||||
},
|
|
||||||
"bySource": {
|
|
||||||
"0 app_app": 21,
|
|
||||||
"0 app_sw": 898
|
|
||||||
},
|
|
||||||
"usedIds": [
|
|
||||||
21,
|
|
||||||
898
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"modules": {
|
|
||||||
"byIdentifier": {
|
|
||||||
"./node_modules/.pnpm/babel-loader@8.2.5_qqaml4ljchhh37dxp4aoesgrby/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!./client/src/js/lib/log.js": 729,
|
|
||||||
"./node_modules/.pnpm/babel-loader@8.2.5_qqaml4ljchhh37dxp4aoesgrby/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!./client/src/js/types/app.js": 617,
|
|
||||||
"./node_modules/.pnpm/babel-loader@8.2.5_qqaml4ljchhh37dxp4aoesgrby/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!./client/src/js/types/sw.js": 647,
|
|
||||||
"./node_modules/.pnpm/babel-loader@8.2.5_qqaml4ljchhh37dxp4aoesgrby/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!./client/src/thirdparty/serviceworker-caches.js": 671
|
|
||||||
},
|
|
||||||
"usedIds": [
|
|
||||||
617,
|
|
||||||
647,
|
|
||||||
671,
|
|
||||||
729
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
38
client/dist/report.html
vendored
38
client/dist/report.html
vendored
File diff suppressed because one or more lines are too long
@ -1,7 +0,0 @@
|
|||||||
const log = (msg) => {
|
|
||||||
if (debug) {
|
|
||||||
console.log(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = log;
|
|
@ -1,13 +0,0 @@
|
|||||||
// Register service worker
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
const baseHref = (document.getElementsByTagName('base')[0] || {}).href;
|
|
||||||
const version = (document.querySelector('meta[name="swversion"]') || {})
|
|
||||||
.content;
|
|
||||||
if (baseHref) {
|
|
||||||
navigator.serviceWorker
|
|
||||||
.register(`${baseHref}sw.js?v=${version}`)
|
|
||||||
.then(() => {
|
|
||||||
console.log('SW: Registered');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
// caches polyfill because it is not added to native yet!
|
|
||||||
var log = require('../lib/log');
|
|
||||||
var caches = require('../../thirdparty/serviceworker-caches');
|
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
log('SW: debug is on');
|
|
||||||
log(`SW: CACHE_NAME: ${CACHE_NAME}`);
|
|
||||||
log(`SW: appDomain: ${appDomain}`);
|
|
||||||
log(`SW: lang: ${lang}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof self.CACHE_NAME !== 'string') {
|
|
||||||
throw new Error('Cache Name cannot be empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
self.addEventListener('fetch', (event) => {
|
|
||||||
// skip non-get
|
|
||||||
if (event.request.method !== 'GET') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Parse the url
|
|
||||||
const requestURL = new URL(event.request.url);
|
|
||||||
|
|
||||||
//Check for our own urls
|
|
||||||
/*if (requestURL.origin !== location.origin) {
|
|
||||||
log('SW: skip external ' + event.request.url);
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// skip captchas
|
|
||||||
if (
|
|
||||||
requestURL.pathname.indexOf('turnstile') >= 0
|
|
||||||
){
|
|
||||||
log(`SW: skip captcha ${event.request.url}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Skip admin url's
|
|
||||||
if (
|
|
||||||
requestURL.pathname.indexOf('admin') >= 0 ||
|
|
||||||
requestURL.pathname.indexOf('Security') >= 0 ||
|
|
||||||
requestURL.pathname.indexOf('dev') >= 0
|
|
||||||
) {
|
|
||||||
log(`SW: skip admin ${event.request.url}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Test for images
|
|
||||||
/*if (/\.(jpg|jpeg|png|gif|webp)$/.test(requestURL.pathname)) {
|
|
||||||
log('SW: skip image ' + event.request.url);
|
|
||||||
//For now we skip images but change this later to maybe some caching and/or an offline fallback
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Clone the request for fetch and cache
|
|
||||||
// A request is a stream and can be consumed only once.
|
|
||||||
const fetchRequest = event.request.clone(),
|
|
||||||
cacheRequest = event.request.clone();
|
|
||||||
|
|
||||||
// Respond with content from fetch or cache
|
|
||||||
event.respondWith(
|
|
||||||
// Try fetch
|
|
||||||
fetch(fetchRequest)
|
|
||||||
// when fetch is successful, we update the cache
|
|
||||||
.then((response) => {
|
|
||||||
// A response is a stream and can be consumed only once.
|
|
||||||
// Because we want the browser to consume the response,
|
|
||||||
// as well as cache to consume the response, we need to
|
|
||||||
// clone it so we have 2 streams
|
|
||||||
const responseToCache = response.clone();
|
|
||||||
|
|
||||||
// and update the cache
|
|
||||||
caches.open(self.CACHE_NAME).then((cache) => {
|
|
||||||
// Clone the request again to use it
|
|
||||||
// as the key for our cache
|
|
||||||
const cacheSaveRequest = event.request.clone();
|
|
||||||
cache.put(cacheSaveRequest, responseToCache);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return the response stream to be consumed by browser
|
|
||||||
return response;
|
|
||||||
})
|
|
||||||
|
|
||||||
// when fetch times out or fails
|
|
||||||
.catch((err) => {
|
|
||||||
log('SW: fetch failed');
|
|
||||||
// Return the promise which
|
|
||||||
// resolves on a match in cache for the current request
|
|
||||||
// or rejects if no matches are found
|
|
||||||
return caches.match(cacheRequest);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Now we need to clean up resources in the previous versions
|
|
||||||
// of Service Worker scripts
|
|
||||||
self.addEventListener('activate', (event) => {
|
|
||||||
log(`SW: activated: ${version}`);
|
|
||||||
// Destroy the cache
|
|
||||||
event.waitUntil(caches.delete(self.CACHE_NAME));
|
|
||||||
});
|
|
||||||
|
|
||||||
self.addEventListener('fetch', (event) => {
|
|
||||||
const request = event.request;
|
|
||||||
|
|
||||||
event.respondWith(
|
|
||||||
caches.match(request)
|
|
||||||
.then((response) => {
|
|
||||||
return response || fetch(request)
|
|
||||||
.then((response) => {
|
|
||||||
return response;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
// Offline fallback image
|
|
||||||
if (request.url.match(/\.(jpe?g|png|gif|svg)$/)) {
|
|
||||||
return new Response(
|
|
||||||
'<svg role="img" aria-labelledby="offline-title" viewBox="0 0 400 225" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice"><title id="offline-title">Offline</title><path fill="rgba(145,145,145,0.5)" d="M0 0h400v225H0z" /><text fill="rgba(0,0,0,0.33)" font-family="Helvetica Neue,Arial,sans-serif" font-size="27" text-anchor="middle" x="200" y="113" dominant-baseline="central">offline</text></svg>',
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'image/svg+xml',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
self.addEventListener('install', (e) => {
|
|
||||||
log(`SW: installing version: ${version}`);
|
|
||||||
});
|
|
259
client/src/thirdparty/google-analytics-offline.js
vendored
259
client/src/thirdparty/google-analytics-offline.js
vendored
@ -1,259 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All Rights Reserved.
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// While overkill for this specific sample in which there is only one cache,
|
|
||||||
// this is one best practice that can be followed in general to keep track of
|
|
||||||
// multiple caches used by a given service worker, and keep them all versioned.
|
|
||||||
// It maps a shorthand identifier for a cache to a specific, versioned cache name.
|
|
||||||
|
|
||||||
// Note that since global state is discarded in between service worker restarts, these
|
|
||||||
// variables will be reinitialized each time the service worker handles an event, and you
|
|
||||||
// should not attempt to change their values inside an event handler. (Treat them as constants.)
|
|
||||||
|
|
||||||
// If at any point you want to force pages that use this service worker to start using a fresh
|
|
||||||
// cache, then increment the CACHE_VERSION value. It will kick off the service worker update
|
|
||||||
// flow and the old cache(s) will be purged as part of the activate event handler when the
|
|
||||||
// updated service worker is activated.
|
|
||||||
var CACHE_VERSION = 1;
|
|
||||||
var CURRENT_CACHES = {
|
|
||||||
'offline-analytics': `offline-analytics-v${ CACHE_VERSION}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
var idbDatabase;
|
|
||||||
var IDB_VERSION = 1;
|
|
||||||
var STOP_RETRYING_AFTER = 86400000; // One day, in milliseconds.
|
|
||||||
var STORE_NAME = 'urls';
|
|
||||||
|
|
||||||
// This is basic boilerplate for interacting with IndexedDB. Adapted from
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
|
|
||||||
function openDatabaseAndReplayRequests() {
|
|
||||||
var indexedDBOpenRequest = indexedDB.open('offline-analytics', IDB_VERSION);
|
|
||||||
|
|
||||||
// This top-level error handler will be invoked any time there's an IndexedDB-related error.
|
|
||||||
indexedDBOpenRequest.onerror = function(error) {
|
|
||||||
console.error('IndexedDB error:', error);
|
|
||||||
};
|
|
||||||
|
|
||||||
// This should only execute if there's a need to create a new database for the given IDB_VERSION.
|
|
||||||
indexedDBOpenRequest.onupgradeneeded = function() {
|
|
||||||
this.result.createObjectStore(STORE_NAME, { keyPath: 'url' });
|
|
||||||
};
|
|
||||||
|
|
||||||
// This will execute each time the database is opened.
|
|
||||||
indexedDBOpenRequest.onsuccess = function() {
|
|
||||||
idbDatabase = this.result;
|
|
||||||
replayAnalyticsRequests();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to get the object store that we care about.
|
|
||||||
function getObjectStore(storeName, mode) {
|
|
||||||
return idbDatabase.transaction(storeName, mode).objectStore(storeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function replayAnalyticsRequests() {
|
|
||||||
var savedRequests = [];
|
|
||||||
|
|
||||||
getObjectStore(STORE_NAME).openCursor().onsuccess = function(event) {
|
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB#Using_a_cursor
|
|
||||||
var cursor = event.target.result;
|
|
||||||
|
|
||||||
if (cursor) {
|
|
||||||
// Keep moving the cursor forward and collecting saved requests.
|
|
||||||
savedRequests.push(cursor.value);
|
|
||||||
cursor.continue();
|
|
||||||
} else {
|
|
||||||
// At this point, we have all the saved requests.
|
|
||||||
console.log(
|
|
||||||
'About to replay %d saved Google Analytics requests...',
|
|
||||||
savedRequests.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
savedRequests.forEach((savedRequest) => {
|
|
||||||
var queueTime = Date.now() - savedRequest.timestamp;
|
|
||||||
if (queueTime > STOP_RETRYING_AFTER) {
|
|
||||||
getObjectStore(STORE_NAME, 'readwrite').delete(savedRequest.url);
|
|
||||||
console.log(
|
|
||||||
' Request has been queued for %d milliseconds. ' +
|
|
||||||
'No longer attempting to replay.',
|
|
||||||
queueTime,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// The qt= URL parameter specifies the time delta in between right now, and when the
|
|
||||||
// /collect request was initially intended to be sent. See
|
|
||||||
// https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#qt
|
|
||||||
var requestUrl = `${savedRequest.url }&qt=${ queueTime}`;
|
|
||||||
|
|
||||||
console.log(' Replaying', requestUrl);
|
|
||||||
|
|
||||||
fetch(requestUrl)
|
|
||||||
.then((response) => {
|
|
||||||
if (response.status < 400) {
|
|
||||||
// If sending the /collect request was successful, then remove it from the IndexedDB.
|
|
||||||
getObjectStore(STORE_NAME, 'readwrite').delete(
|
|
||||||
savedRequest.url,
|
|
||||||
);
|
|
||||||
console.log(' Replaying succeeded.');
|
|
||||||
} else {
|
|
||||||
// This will be triggered if, e.g., Google Analytics returns a HTTP 50x response.
|
|
||||||
// The request will be replayed the next time the service worker starts up.
|
|
||||||
console.error(' Replaying failed:', response);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
// This will be triggered if the network is still down. The request will be replayed again
|
|
||||||
// the next time the service worker starts up.
|
|
||||||
console.error(' Replaying failed:', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the IndexedDB and check for requests to replay each time the service worker starts up.
|
|
||||||
// Since the service worker is terminated fairly frequently, it should start up again for most
|
|
||||||
// page navigations. It also might start up if it's used in a background sync or a push
|
|
||||||
// notification context.
|
|
||||||
openDatabaseAndReplayRequests();
|
|
||||||
|
|
||||||
self.addEventListener('activate', (event) => {
|
|
||||||
// Delete all caches that aren't named in CURRENT_CACHES.
|
|
||||||
// While there is only one cache in this example, the same logic will handle the case where
|
|
||||||
// there are multiple versioned caches.
|
|
||||||
var expectedCacheNames = Object.keys(CURRENT_CACHES).map((key) => {
|
|
||||||
return CURRENT_CACHES[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
event.waitUntil(
|
|
||||||
// `caches` refers to the global CacheStorage object, and is defined at
|
|
||||||
// http://slightlyoff.github.io/ServiceWorker/spec/service_worker/#self-caches
|
|
||||||
caches.keys().then((cacheNames) => {
|
|
||||||
return Promise.all(
|
|
||||||
cacheNames.map((cacheName) => {
|
|
||||||
if (expectedCacheNames.indexOf(cacheName) === -1) {
|
|
||||||
// If this cache name isn't present in the array of "expected" cache names, then delete it.
|
|
||||||
console.log('Deleting out of date cache:', cacheName);
|
|
||||||
return caches.delete(cacheName);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// This sample illustrates an aggressive approach to caching, in which every valid response is
|
|
||||||
// cached and every request is first checked against the cache.
|
|
||||||
// This may not be an appropriate approach if your web application makes requests for
|
|
||||||
// arbitrary URLs as part of its normal operation (e.g. a RSS client or a news aggregator),
|
|
||||||
// as the cache could end up containing large responses that might not end up ever being accessed.
|
|
||||||
// Other approaches, like selectively caching based on response headers or only caching
|
|
||||||
// responses served from a specific domain, might be more appropriate for those use cases.
|
|
||||||
self.addEventListener('fetch', (event) => {
|
|
||||||
console.log('Handling fetch event for', event.request.url);
|
|
||||||
|
|
||||||
event.respondWith(
|
|
||||||
caches.open(CURRENT_CACHES['offline-analytics']).then((cache) => {
|
|
||||||
return cache
|
|
||||||
.match(event.request)
|
|
||||||
.then((response) => {
|
|
||||||
if (response) {
|
|
||||||
// If there is an entry in the cache for event.request, then response will be defined
|
|
||||||
// and we can just return it.
|
|
||||||
console.log(' Found response in cache:', response);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, if there is no entry in the cache for event.request, response will be
|
|
||||||
// undefined, and we need to fetch() the resource.
|
|
||||||
console.log(
|
|
||||||
' No response for %s found in cache. ' +
|
|
||||||
'About to fetch from network...',
|
|
||||||
event.request.url,
|
|
||||||
);
|
|
||||||
|
|
||||||
// We call .clone() on the request since we might use it in the call to cache.put() later on.
|
|
||||||
// Both fetch() and cache.put() "consume" the request, so we need to make a copy.
|
|
||||||
// (see https://fetch.spec.whatwg.org/#dom-request-clone)
|
|
||||||
return fetch(event.request.clone())
|
|
||||||
.then((response) => {
|
|
||||||
console.log(
|
|
||||||
' Response for %s from network is: %O',
|
|
||||||
event.request.url,
|
|
||||||
response,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Optional: add in extra conditions here, e.g. response.type == 'basic' to only cache
|
|
||||||
// responses from the same domain. See https://fetch.spec.whatwg.org/#concept-response-type
|
|
||||||
if (response.status < 400) {
|
|
||||||
// This avoids caching responses that we know are errors (i.e. HTTP status code of 4xx or 5xx).
|
|
||||||
// One limitation is that, for non-CORS requests, we get back a filtered opaque response
|
|
||||||
// (https://fetch.spec.whatwg.org/#concept-filtered-response-opaque) which will always have a
|
|
||||||
// .status of 0, regardless of whether the underlying HTTP call was successful. Since we're
|
|
||||||
// blindly caching those opaque responses, we run the risk of caching a transient error response.
|
|
||||||
//
|
|
||||||
// We need to call .clone() on the response object to save a copy of it to the cache.
|
|
||||||
// (https://fetch.spec.whatwg.org/#dom-request-clone)
|
|
||||||
cache.put(event.request, response.clone());
|
|
||||||
} else if (response.status >= 500) {
|
|
||||||
// If this is a Google Analytics ping then we want to retry it if a HTTP 5xx response
|
|
||||||
// was returned, just like we'd retry it if the network was down.
|
|
||||||
checkForAnalyticsRequest(event.request.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the original response object, which will be used to fulfill the resource request.
|
|
||||||
return response;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
// The catch() will be triggered for network failures. Let's see if it was a request for
|
|
||||||
// a Google Analytics ping, and save it to be retried if it was.
|
|
||||||
checkForAnalyticsRequest(event.request.url);
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
// This catch() will handle exceptions that arise from the match() or fetch() operations.
|
|
||||||
// Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
|
|
||||||
// It will return a normal response object that has the appropriate error code set.
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
function checkForAnalyticsRequest(requestUrl) {
|
|
||||||
// Construct a URL object (https://developer.mozilla.org/en-US/docs/Web/API/URL.URL)
|
|
||||||
// to make it easier to check the various components without dealing with string parsing.
|
|
||||||
var url = new URL(requestUrl);
|
|
||||||
|
|
||||||
if (
|
|
||||||
(url.hostname === 'www.google-analytics.com' ||
|
|
||||||
url.hostname === 'ssl.google-analytics.com') &&
|
|
||||||
url.pathname === '/collect'
|
|
||||||
) {
|
|
||||||
console.log(
|
|
||||||
' Storing Google Analytics request in IndexedDB ' +
|
|
||||||
'to be replayed later.',
|
|
||||||
);
|
|
||||||
saveAnalyticsRequest(requestUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveAnalyticsRequest(requestUrl) {
|
|
||||||
getObjectStore(STORE_NAME, 'readwrite').add({
|
|
||||||
url: requestUrl,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
});
|
|
||||||
}
|
|
93
client/src/thirdparty/serviceworker-caches.js
vendored
93
client/src/thirdparty/serviceworker-caches.js
vendored
@ -1,93 +0,0 @@
|
|||||||
if (!Cache.prototype.add) {
|
|
||||||
Cache.prototype.add = function add(request) {
|
|
||||||
return this.addAll([request]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Cache.prototype.addAll) {
|
|
||||||
Cache.prototype.addAll = function addAll(requests) {
|
|
||||||
var cache = this;
|
|
||||||
|
|
||||||
// Since DOMExceptions are not constructable:
|
|
||||||
function NetworkError(message) {
|
|
||||||
this.name = 'NetworkError';
|
|
||||||
this.code = 19;
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
NetworkError.prototype = Object.create(Error.prototype);
|
|
||||||
|
|
||||||
return Promise.resolve()
|
|
||||||
.then(function() {
|
|
||||||
if (arguments.length < 1) throw new TypeError();
|
|
||||||
|
|
||||||
// Simulate sequence<(Request or USVString)> binding:
|
|
||||||
var sequence = [];
|
|
||||||
|
|
||||||
requests = requests.map((request) => {
|
|
||||||
if (request instanceof Request) {
|
|
||||||
return request;
|
|
||||||
} else {
|
|
||||||
return String(request); // may throw TypeError
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(
|
|
||||||
requests.map((request) => {
|
|
||||||
if (typeof request === 'string') {
|
|
||||||
request = new Request(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
var scheme = new URL(request.url).protocol;
|
|
||||||
|
|
||||||
if (scheme !== 'http:' && scheme !== 'https:') {
|
|
||||||
throw new NetworkError('Invalid scheme');
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetch(request.clone());
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.then((responses) => {
|
|
||||||
// TODO: check that requests don't overwrite one another
|
|
||||||
// (don't think this is possible to polyfill due to opaque responses)
|
|
||||||
return Promise.all(
|
|
||||||
responses.map((response, i) => {
|
|
||||||
return cache.put(requests[i], response);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CacheStorage.prototype.match) {
|
|
||||||
// This is probably vulnerable to race conditions (removing caches etc)
|
|
||||||
CacheStorage.prototype.match = function match(request, opts) {
|
|
||||||
var caches = this;
|
|
||||||
|
|
||||||
return this.keys().then((cacheNames) => {
|
|
||||||
var match;
|
|
||||||
|
|
||||||
return cacheNames.reduce((chain, cacheName) => {
|
|
||||||
return chain.then(() => {
|
|
||||||
return (
|
|
||||||
match ||
|
|
||||||
caches
|
|
||||||
.open(cacheName)
|
|
||||||
.then((cache) => {
|
|
||||||
return cache.match(request, opts);
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
match = response;
|
|
||||||
return match;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}, Promise.resolve());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = self.caches;
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "a2nt/silverstripe-progressivewebapp",
|
"name": "pixelspin/silverstripe-progressivewebapp",
|
||||||
"description": "Tools to add offline caching and the other progressive web app functionality to your silverstripe website",
|
"description": "Tools to add progressive web app functionality to your silverstripe website",
|
||||||
"type": "silverstripe-vendormodule",
|
"type": "silverstripe-vendormodule",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"silverstripe",
|
"silverstripe",
|
||||||
@ -8,29 +8,33 @@
|
|||||||
"app"
|
"app"
|
||||||
],
|
],
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"authors": [
|
"authors": [{
|
||||||
{
|
"name": "Michel van der Steege",
|
||||||
"name": "Tony Air",
|
"email": "michelsteege@hotmail.com"
|
||||||
"email": "tony@twma.pro"
|
|
||||||
}],
|
}],
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"require":
|
"prefer-stable": true,
|
||||||
{
|
"require": {
|
||||||
"silverstripe/cms": "*"
|
"silverstripe/cms": "^4.0@dev",
|
||||||
|
"silverstripe/vendor-plugin": "^1.0",
|
||||||
|
"silverware/colorpicker": "^1.0"
|
||||||
},
|
},
|
||||||
"extra":
|
"require-dev": {
|
||||||
{
|
"phpunit/phpunit": "^5.7",
|
||||||
|
"squizlabs/php_codesniffer": "^3.0"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
"installer-name": "silverstripe-progressivewebapp",
|
"installer-name": "silverstripe-progressivewebapp",
|
||||||
"branch-alias":
|
"branch-alias": {
|
||||||
{
|
|
||||||
"dev-master": "2.x-dev"
|
"dev-master": "2.x-dev"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"autoload":
|
"expose": [
|
||||||
{
|
"resources"
|
||||||
"psr-4":
|
]
|
||||||
{
|
},
|
||||||
"A2nt\\ProgressiveWebApp\\": "src/"
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Pixelspin\\ProgressiveWebApp\\": "src/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,272 +0,0 @@
|
|||||||
{
|
|
||||||
// http://eslint.org/docs/rules/
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
|
|
||||||
"settings": {
|
|
||||||
"react": {
|
|
||||||
"version": "detect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"env": {
|
|
||||||
"browser": true, // browser global variables.
|
|
||||||
"node": true, // Node.js global variables and Node.js-specific rules.
|
|
||||||
"amd": true, // defines require() and define() as global variables as per the amd spec.
|
|
||||||
"mocha": false, // adds all of the Mocha testing global variables.
|
|
||||||
"jasmine": false, // adds all of the Jasmine testing global variables for version 1.3 and 2.0.
|
|
||||||
"phantomjs": false, // phantomjs global variables.
|
|
||||||
"jquery": true, // jquery global variables.
|
|
||||||
"prototypejs": false, // prototypejs global variables.
|
|
||||||
"shelljs": false, // shelljs global variables.
|
|
||||||
"es6": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"globals": {
|
|
||||||
// e.g. "angular": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"plugins": ["react", "import", "jquery"],
|
|
||||||
|
|
||||||
"parser": "@babel/eslint-parser",
|
|
||||||
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 6,
|
|
||||||
"sourceType": "module",
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true,
|
|
||||||
"experimentalObjectRestSpread": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"rules": {
|
|
||||||
////////// Possible Errors //////////
|
|
||||||
|
|
||||||
"no-comma-dangle": 0, // disallow trailing commas in object literals
|
|
||||||
"no-cond-assign": 0, // disallow assignment in conditional expressions
|
|
||||||
"no-console": 0, // disallow use of console (off by default in the node environment)
|
|
||||||
"no-constant-condition": 0, // disallow use of constant expressions in conditions
|
|
||||||
"no-control-regex": 0, // disallow control characters in regular expressions
|
|
||||||
"no-debugger": 0, // disallow use of debugger
|
|
||||||
"no-dupe-keys": 0, // disallow duplicate keys when creating object literals
|
|
||||||
"no-empty": 0, // disallow empty statements
|
|
||||||
"no-empty-class": 0, // disallow the use of empty character classes in regular expressions
|
|
||||||
"no-ex-assign": 0, // disallow assigning to the exception in a catch block
|
|
||||||
"no-extra-boolean-cast": 0, // disallow double-negation boolean casts in a boolean context
|
|
||||||
"no-extra-parens": 0, // disallow unnecessary parentheses (off by default)
|
|
||||||
"no-extra-semi": 0, // disallow unnecessary semicolons
|
|
||||||
"no-func-assign": 0, // disallow overwriting functions written as function declarations
|
|
||||||
"no-inner-declarations": 0, // disallow function or variable declarations in nested blocks
|
|
||||||
"no-invalid-regexp": 0, // disallow invalid regular expression strings in the RegExp constructor
|
|
||||||
"no-irregular-whitespace": 0, // disallow irregular whitespace outside of strings and comments
|
|
||||||
"no-negated-in-lhs": 0, // disallow negation of the left operand of an in expression
|
|
||||||
"no-obj-calls": 0, // disallow the use of object properties of the global object (Math and JSON) as functions
|
|
||||||
"no-regex-spaces": 0, // disallow multiple spaces in a regular expression literal
|
|
||||||
"no-reserved-keys": 0, // disallow reserved words being used as object literal keys (off by default)
|
|
||||||
"no-sparse-arrays": 0, // disallow sparse arrays
|
|
||||||
"no-unreachable": 0, // disallow unreachable statements after a return, throw, continue, or break statement
|
|
||||||
"use-isnan": 0, // disallow comparisons with the value NaN
|
|
||||||
"valid-jsdoc": 0, // Ensure JSDoc comments are valid (off by default)
|
|
||||||
"valid-typeof": 0, // Ensure that the results of typeof are compared against a valid string
|
|
||||||
|
|
||||||
////////// Best Practices //////////
|
|
||||||
|
|
||||||
"block-scoped-var": 0, // treat var statements as if they were block scoped (off by default)
|
|
||||||
"complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default)
|
|
||||||
"consistent-return": 0, // require return statements to either always or never specify values
|
|
||||||
"curly": 0, // specify curly brace conventions for all control statements
|
|
||||||
"default-case": 0, // require default case in switch statements (off by default)
|
|
||||||
"dot-notation": 0, // encourages use of dot notation whenever possible
|
|
||||||
"eqeqeq": 0, // require the use of === and !==
|
|
||||||
"guard-for-in": 0, // make sure for-in loops have an if statement (off by default)
|
|
||||||
"no-alert": 0, // disallow the use of alert, confirm, and prompt
|
|
||||||
"no-caller": 0, // disallow use of arguments.caller or arguments.callee
|
|
||||||
"no-div-regex": 0, // disallow division operators explicitly at beginning of regular expression (off by default)
|
|
||||||
"no-else-return": 0, // disallow else after a return in an if (off by default)
|
|
||||||
"no-empty-label": 0, // disallow use of labels for anything other then loops and switches
|
|
||||||
"no-eq-null": 0, // disallow comparisons to null without a type-checking operator (off by default)
|
|
||||||
"no-eval": 0, // disallow use of eval()
|
|
||||||
"no-extend-native": 0, // disallow adding to native types
|
|
||||||
"no-extra-bind": 0, // disallow unnecessary function binding
|
|
||||||
"no-fallthrough": 0, // disallow fallthrough of case statements
|
|
||||||
"no-floating-decimal": 0, // disallow the use of leading or trailing decimal points in numeric literals (off by default)
|
|
||||||
"no-implied-eval": 0, // disallow use of eval()-like methods
|
|
||||||
"no-iterator": 0, // disallow usage of __iterator__ property
|
|
||||||
"no-labels": 0, // disallow use of labeled statements
|
|
||||||
"no-lone-blocks": 0, // disallow unnecessary nested blocks
|
|
||||||
"no-loop-func": 0, // disallow creation of functions within loops
|
|
||||||
"no-multi-spaces": 0, // disallow use of multiple spaces
|
|
||||||
"no-multi-str": 0, // disallow use of multiline strings
|
|
||||||
"no-native-reassign": 0, // disallow reassignments of native objects
|
|
||||||
"no-new": 0, // disallow use of new operator when not part of the assignment or comparison
|
|
||||||
"no-new-func": 0, // disallow use of new operator for Function object
|
|
||||||
"no-new-wrappers": 0, // disallows creating new instances of String, Number, and Boolean
|
|
||||||
"no-octal": 0, // disallow use of octal literals
|
|
||||||
"no-octal-escape": 0, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251";
|
|
||||||
"no-process-env": 0, // disallow use of process.env (off by default)
|
|
||||||
"no-proto": 0, // disallow usage of __proto__ property
|
|
||||||
"no-redeclare": 0, // disallow declaring the same variable more then once
|
|
||||||
"no-return-assign": 0, // disallow use of assignment in return statement
|
|
||||||
"no-script-url": 0, // disallow use of javascript: urls.
|
|
||||||
"no-self-compare": 0, // disallow comparisons where both sides are exactly the same (off by default)
|
|
||||||
"no-sequences": 0, // disallow use of comma operator
|
|
||||||
"no-unused-expressions": 0, // disallow usage of expressions in statement position
|
|
||||||
"no-void": 0, // disallow use of void operator (off by default)
|
|
||||||
"no-warning-comments": 0, // disallow usage of configurable warning terms in comments, e.g. TODO or FIXME (off by default)
|
|
||||||
"no-with": 0, // disallow use of the with statement
|
|
||||||
"radix": 0, // require use of the second argument for parseInt() (off by default)
|
|
||||||
"vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default)
|
|
||||||
"wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default)
|
|
||||||
"yoda": 0, // require or disallow Yoda conditions
|
|
||||||
|
|
||||||
////////// Strict Mode //////////
|
|
||||||
|
|
||||||
"global-strict": 0, // (deprecated) require or disallow the "use strict" pragma in the global scope (off by default in the node environment)
|
|
||||||
"no-extra-strict": 0, // (deprecated) disallow unnecessary use of "use strict"; when already in strict mode
|
|
||||||
"strict": 0, // controls location of Use Strict Directives
|
|
||||||
|
|
||||||
////////// Variables //////////
|
|
||||||
|
|
||||||
"no-catch-shadow": 0, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment)
|
|
||||||
"no-delete-var": 0, // disallow deletion of variables
|
|
||||||
"no-label-var": 0, // disallow labels that share a name with a variable
|
|
||||||
"no-shadow": 0, // disallow declaration of variables already declared in the outer scope
|
|
||||||
"no-shadow-restricted-names": 0, // disallow shadowing of names such as arguments
|
|
||||||
"no-undef": 0, // disallow use of undeclared variables unless mentioned in a /*global */ block
|
|
||||||
"no-undef-init": 0, // disallow use of undefined when initializing variables
|
|
||||||
"no-undefined": 0, // disallow use of undefined variable (off by default)
|
|
||||||
"no-unused-vars": 0, // disallow declaration of variables that are not used in the code
|
|
||||||
"no-use-before-define": 0, // disallow use of variables before they are defined
|
|
||||||
|
|
||||||
////////// Node.js //////////
|
|
||||||
|
|
||||||
"handle-callback-err": 0, // enforces error handling in callbacks (off by default) (on by default in the node environment)
|
|
||||||
"no-mixed-requires": 0, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment)
|
|
||||||
"no-new-require": 0, // disallow use of new operator with the require function (off by default) (on by default in the node environment)
|
|
||||||
"no-path-concat": 0, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment)
|
|
||||||
"no-process-exit": 0, // disallow process.exit() (on by default in the node environment)
|
|
||||||
"no-restricted-modules": 0, // restrict usage of specified node modules (off by default)
|
|
||||||
"no-sync": 0, // disallow use of synchronous methods (off by default)
|
|
||||||
|
|
||||||
////////// Stylistic Issues //////////
|
|
||||||
|
|
||||||
"brace-style": 0, // enforce one true brace style (off by default)
|
|
||||||
"camelcase": 0, // require camel case names
|
|
||||||
"comma-spacing": 0, // enforce spacing before and after comma
|
|
||||||
"comma-style": 0, // enforce one true comma style (off by default)
|
|
||||||
"consistent-this": 0, // enforces consistent naming when capturing the current execution context (off by default)
|
|
||||||
"eol-last": 0, // enforce newline at the end of file, with no multiple empty lines
|
|
||||||
"func-names": 0, // require function expressions to have a name (off by default)
|
|
||||||
"func-style": 0, // enforces use of function declarations or expressions (off by default)
|
|
||||||
"key-spacing": 0, // enforces spacing between keys and values in object literal properties
|
|
||||||
"max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested (off by default)
|
|
||||||
"new-cap": 0, // require a capital letter for constructors
|
|
||||||
"new-parens": 0, // disallow the omission of parentheses when invoking a constructor with no arguments
|
|
||||||
"no-array-constructor": 0, // disallow use of the Array constructor
|
|
||||||
"no-inline-comments": 0, // disallow comments inline after code (off by default)
|
|
||||||
"no-lonely-if": 0, // disallow if as the only statement in an else block (off by default)
|
|
||||||
"no-mixed-spaces-and-tabs": 0, // disallow mixed spaces and tabs for indentation
|
|
||||||
"no-multiple-empty-lines": 0, // disallow multiple empty lines (off by default)
|
|
||||||
"no-nested-ternary": 0, // disallow nested ternary expressions (off by default)
|
|
||||||
"no-new-object": 0, // disallow use of the Object constructor
|
|
||||||
"no-space-before-semi": 0, // disallow space before semicolon
|
|
||||||
"no-spaced-func": 0, // disallow space between function identifier and application
|
|
||||||
"no-ternary": 0, // disallow the use of ternary operators (off by default)
|
|
||||||
"no-trailing-spaces": 0, // disallow trailing whitespace at the end of lines
|
|
||||||
"no-underscore-dangle": 0, // disallow dangling underscores in identifiers
|
|
||||||
"no-wrap-func": 0, // disallow wrapping of non-IIFE statements in parens
|
|
||||||
"one-var": 0, // allow just one var statement per function (off by default)
|
|
||||||
"operator-assignment": 0, // require assignment operator shorthand where possible or prohibit it entirely (off by default)
|
|
||||||
"padded-blocks": 0, // enforce padding within blocks (off by default)
|
|
||||||
"quote-props": 0, // require quotes around object literal property names (off by default)
|
|
||||||
"quotes": 0, // specify whether double or single quotes should be used
|
|
||||||
"semi": 0, // require or disallow use of semicolons instead of ASI
|
|
||||||
"sort-vars": 0, // sort variables within the same declaration block (off by default)
|
|
||||||
"space-after-function-name": 0, // require a space after function names (off by default)
|
|
||||||
"space-after-keywords": 0, // require a space after certain keywords (off by default)
|
|
||||||
"space-before-blocks": 0, // require or disallow space before blocks (off by default)
|
|
||||||
"space-in-brackets": 0, // require or disallow spaces inside brackets (off by default)
|
|
||||||
"space-in-parens": 0, // require or disallow spaces inside parentheses (off by default)
|
|
||||||
"space-infix-ops": 0, // require spaces around operators
|
|
||||||
"space-return-throw-case": 0, // require a space after return, throw, and case
|
|
||||||
"space-unary-ops": 0, // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default)
|
|
||||||
"spaced-line-comment": 0, // require or disallow a space immediately following the // in a line comment (off by default)
|
|
||||||
"wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default)
|
|
||||||
|
|
||||||
////////// ECMAScript 6 //////////
|
|
||||||
|
|
||||||
"no-var": 0, // require let or const instead of var (off by default)
|
|
||||||
"generator-star": 0, // enforce the position of the * in generator functions (off by default)
|
|
||||||
|
|
||||||
////////// Legacy //////////
|
|
||||||
|
|
||||||
"max-depth": 0, // specify the maximum depth that blocks can be nested (off by default)
|
|
||||||
"max-len": 0, // specify the maximum length of a line in your program (off by default)
|
|
||||||
"max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default)
|
|
||||||
"max-statements": 0, // specify the maximum number of statement allowed in a function (off by default)
|
|
||||||
"no-bitwise": 0, // disallow use of bitwise operators (off by default)
|
|
||||||
"no-plusplus": 0, // disallow use of unary operators, ++ and -- (off by default)
|
|
||||||
|
|
||||||
//////// Extra //////////
|
|
||||||
"array-bracket-spacing": ["error", "never"],
|
|
||||||
"array-callback-return": "error",
|
|
||||||
"arrow-parens": ["error", "always"],
|
|
||||||
"arrow-spacing": ["error", { "before": true, "after": true }],
|
|
||||||
"comma-dangle": ["error", "always-multiline"],
|
|
||||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
|
||||||
"no-case-declarations": "error",
|
|
||||||
"no-confusing-arrow": "error",
|
|
||||||
"no-duplicate-imports": "error",
|
|
||||||
"no-param-reassign": "error",
|
|
||||||
"no-useless-escape": "error",
|
|
||||||
"object-curly-spacing": ["error", "always"],
|
|
||||||
"object-shorthand": ["error", "properties"],
|
|
||||||
"prefer-arrow-callback": "error",
|
|
||||||
"prefer-const": "error",
|
|
||||||
"prefer-template": "error",
|
|
||||||
"react/jsx-closing-bracket-location": "error",
|
|
||||||
"react/jsx-curly-spacing": [
|
|
||||||
"error",
|
|
||||||
"never",
|
|
||||||
{ "allowMultiline": true }
|
|
||||||
],
|
|
||||||
"react/jsx-filename-extension": [
|
|
||||||
"error",
|
|
||||||
{ "extensions": [".react.js", ".js", ".jsx"] }
|
|
||||||
],
|
|
||||||
"react/jsx-no-duplicate-props": "error",
|
|
||||||
"react/jsx-no-bind": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"ignoreRefs": true,
|
|
||||||
"allowArrowFunctions": true,
|
|
||||||
"allowBind": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"react/jsx-no-undef": "error",
|
|
||||||
"react/jsx-pascal-case": "error",
|
|
||||||
"react/jsx-tag-spacing": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"closingSlash": "never",
|
|
||||||
"beforeSelfClosing": "always",
|
|
||||||
"afterOpening": "never"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"react/jsx-uses-react": "error",
|
|
||||||
"react/jsx-uses-vars": "error",
|
|
||||||
"react/no-danger": "error",
|
|
||||||
"react/no-deprecated": "error",
|
|
||||||
"react/no-did-mount-set-state": "error",
|
|
||||||
"react/no-did-update-set-state": "error",
|
|
||||||
"react/no-direct-mutation-state": "error",
|
|
||||||
"react/no-is-mounted": "error",
|
|
||||||
"react/no-multi-comp": "error",
|
|
||||||
"react/prefer-es6-class": "error",
|
|
||||||
"react/prop-types": "error",
|
|
||||||
"react/require-render-return": "error",
|
|
||||||
"react/self-closing-comp": "error",
|
|
||||||
"react/sort-comp": "error",
|
|
||||||
"import/no-mutable-exports": "error",
|
|
||||||
"import/imports-first": "warn"
|
|
||||||
}
|
|
||||||
}
|
|
232
package.json
232
package.json
@ -1,232 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ss-webpack-boilerplate",
|
|
||||||
"version": "5.0.0",
|
|
||||||
"description": "Lets you create SilverStripe faster",
|
|
||||||
"author": "Tony Air <tony@twma.pro>",
|
|
||||||
"license": "MIT",
|
|
||||||
"private": false,
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/a2nt/silverstripe-webpack"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"yarn": ">= 1.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.serve.js",
|
|
||||||
"dash": "cross-env NODE_ENV=development webpack-dashboard -- webpack-dev-server --config webpack.config.serve.js",
|
|
||||||
"prebuild": "yarn lint:fix && yarn lint:check && rimraf ./client/dist",
|
|
||||||
"build": "cross-env NODE_ENV=production webpack --progress --stats-all",
|
|
||||||
"lint:fix": "eslint './client/src/**/*.js' -c eslint.config.json --fix",
|
|
||||||
"lint:js": "eslint './client/src/**/*.js' -c eslint.config.json",
|
|
||||||
"lint:scss": "sass-lint ./client/src/**/*.scss -c sass-lint.yml -v",
|
|
||||||
"lint:check": "yarn lint:js && yarn lint:scss",
|
|
||||||
"prunecaches": "rimraf ./node_modules/.cache/",
|
|
||||||
"postinstall": "npm run prunecaches",
|
|
||||||
"postuninstall": "npm run prunecaches",
|
|
||||||
"preinstall": "npx only-allow pnpm"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"colors": "1.4.0"
|
|
||||||
},
|
|
||||||
"browserslist": [
|
|
||||||
"defaults",
|
|
||||||
"ie>=11"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@a2nt/meta-lightbox-js": "^4.2.2",
|
|
||||||
"@a2nt/ss-bootstrap-ui-webpack-boilerplate-react": "^4.6.1",
|
|
||||||
"@angular/common": "^13.3.5",
|
|
||||||
"@angular/core": "^13.3.5",
|
|
||||||
"@apollo/client": "^3.6.2",
|
|
||||||
"@jsanahuja/instagramfeed": "github:jsanahuja/instagramfeed",
|
|
||||||
"@popperjs/core": "^2.11.5",
|
|
||||||
"@turf/clone": "^6.5.0",
|
|
||||||
"@turf/clusters-dbscan": "^6.5.0",
|
|
||||||
"@turf/clusters-kmeans": "^6.5.0",
|
|
||||||
"@turf/distance": "^6.5.0",
|
|
||||||
"@turf/helpers": "^6.5.0",
|
|
||||||
"@turf/invariant": "^6.5.0",
|
|
||||||
"@turf/meta": "^6.5.0",
|
|
||||||
"aos": "^2.3.4",
|
|
||||||
"apollo3-cache-persist": "^0.14.0",
|
|
||||||
"balanced-match": "^2.0.0",
|
|
||||||
"bootbox": "^5.5.3",
|
|
||||||
"bootstrap": "^5.1.3",
|
|
||||||
"brace-expansion": "^2.0.1",
|
|
||||||
"charming": "^3.0.2",
|
|
||||||
"density-clustering": "^1.3.0",
|
|
||||||
"eslint-scope": "^7.1.1",
|
|
||||||
"fast-deep-equal": "^3.1.3",
|
|
||||||
"font-awesome": "^4.7.0",
|
|
||||||
"graphql": "^16.4.0",
|
|
||||||
"hammerjs": "^2.0.8",
|
|
||||||
"inputmask": "^5.0.7",
|
|
||||||
"kdbush": "^3.0.0",
|
|
||||||
"keyboardjs": "^2.6.4",
|
|
||||||
"localforage": "^1.10.0",
|
|
||||||
"localforage-cordovasqlitedriver": "^1.8.0",
|
|
||||||
"lodash.debounce": "^4.0.8",
|
|
||||||
"lodash.throttle": "^4.1.1",
|
|
||||||
"mapbox-gl": "^2.8.2",
|
|
||||||
"material-design-color": "^2.3.2",
|
|
||||||
"minimatch": "^5.0.1",
|
|
||||||
"moment": "^2.29.3",
|
|
||||||
"react": "^18.1.0",
|
|
||||||
"react-dom": "^18.1.0",
|
|
||||||
"react-easy-swipe": "^0.0.22",
|
|
||||||
"react-tiny-oembed": "^1.1.0",
|
|
||||||
"redaxios": "^0.5.0",
|
|
||||||
"rxjs": "^7.5.5",
|
|
||||||
"select2": "^4.0.13",
|
|
||||||
"setimmediate": "^1.0.5",
|
|
||||||
"skmeans": "^0.11.3",
|
|
||||||
"supercluster": "^7.1.5",
|
|
||||||
"vanilla-calendar": "^1.0.30",
|
|
||||||
"vanillajs-datepicker": "^1.2.0",
|
|
||||||
"youtube-embed": "^1.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@a2nt/image-sprite-webpack-plugin": "^0.2.5",
|
|
||||||
"@babel/core": "^7.17.10",
|
|
||||||
"@babel/eslint-parser": "^7.17.0",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.17.3",
|
|
||||||
"@babel/plugin-syntax-jsx": "^7.16.7",
|
|
||||||
"@babel/plugin-syntax-top-level-await": "^7.14.5",
|
|
||||||
"@babel/plugin-transform-react-jsx": "^7.17.3",
|
|
||||||
"@babel/plugin-transform-runtime": "^7.17.10",
|
|
||||||
"@babel/plugin-transform-typescript": "^7.16.8",
|
|
||||||
"@babel/preset-env": "^7.17.10",
|
|
||||||
"@babel/preset-react": "^7.16.7",
|
|
||||||
"@babel/runtime": "^7.17.9",
|
|
||||||
"@googlemaps/markerclusterer": "*",
|
|
||||||
"@sucrase/webpack-loader": "^2.0.0",
|
|
||||||
"@ungap/global-this": "^0.4.4",
|
|
||||||
"@wry/context": "^0.6.1",
|
|
||||||
"@wry/equality": "^0.5.2",
|
|
||||||
"@wry/trie": "^0.3.1",
|
|
||||||
"animate.css": "^4.1.1",
|
|
||||||
"ansi-html": "^0.0.9",
|
|
||||||
"ansi-html-community": "^0.0.8",
|
|
||||||
"ansi-regex": "^6.0.1",
|
|
||||||
"autoprefixer": "^10.4.7",
|
|
||||||
"babel-loader": "^8.2.5",
|
|
||||||
"classnames": "^2.3.1",
|
|
||||||
"copy-webpack-plugin": "^10.2.4",
|
|
||||||
"croppie": "^2.6.5",
|
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"css-loader": "^6.7.1",
|
|
||||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
|
||||||
"eslint": "^8.14.0",
|
|
||||||
"eslint-plugin-import": "^2.26.0",
|
|
||||||
"eslint-plugin-jquery": "^1.5.1",
|
|
||||||
"eslint-plugin-react": "^7.29.4",
|
|
||||||
"events": "^3.3.0",
|
|
||||||
"exif-js": "^2.3.0",
|
|
||||||
"exports-loader": "^3.1.0",
|
|
||||||
"fast-equals": "^3.0.2",
|
|
||||||
"fast-json-stable-stringify": "^2.1.0",
|
|
||||||
"fast-levenshtein": "^3.0.0",
|
|
||||||
"fastest-levenshtein": "^1.0.12",
|
|
||||||
"favicons": "^6.2.2",
|
|
||||||
"favicons-webpack-plugin": "^5.0.2",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"graphql-tag": "^2.12.6",
|
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
|
||||||
"html-dom-parser": "^1.2.0",
|
|
||||||
"html-entities": "^2.3.3",
|
|
||||||
"html-loader": "^3.1.0",
|
|
||||||
"html-react-parser": "^1.4.12",
|
|
||||||
"html-webpack-plugin": "^5.5.0",
|
|
||||||
"img-optimize-loader": "^1.0.7",
|
|
||||||
"js-yaml": "^4.1.0",
|
|
||||||
"loglevel": "^1.8.0",
|
|
||||||
"mini-css-extract-plugin": "^2.6.0",
|
|
||||||
"msw": "^0.39.2",
|
|
||||||
"node-fetch": "^3.2.4",
|
|
||||||
"object-assign": "^4.1.1",
|
|
||||||
"optimism": "^0.16.1",
|
|
||||||
"optimize-css-assets-webpack-plugin": "^6.0.1",
|
|
||||||
"postcss-loader": "^6.2.1",
|
|
||||||
"prop-types": "^15.8.1",
|
|
||||||
"punycode": "^2.1.1",
|
|
||||||
"querystring": "^0.2.1",
|
|
||||||
"raw-loader": "^4.0.2",
|
|
||||||
"react-hot-loader": "^4.13.0",
|
|
||||||
"react-is": "^18.1.0",
|
|
||||||
"react-lifecycles-compat": "^3.0.4",
|
|
||||||
"regenerator-runtime": "^0.13.9",
|
|
||||||
"resolve-url-loader": "^5.0.0",
|
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"routie": "0.0.1",
|
|
||||||
"sass": "*",
|
|
||||||
"sass-lint": "^1.13.1",
|
|
||||||
"sass-lint-auto-fix": "^0.21.2",
|
|
||||||
"sass-lint-fix": "^1.12.1",
|
|
||||||
"sass-loader": "^12.6.0",
|
|
||||||
"scheduler": "^0.22.0",
|
|
||||||
"shallowequal": "^1.1.0",
|
|
||||||
"strip-ansi": "^7.0.1",
|
|
||||||
"style-loader": "^3.3.1",
|
|
||||||
"sucrase": "^3.21.0",
|
|
||||||
"svg-url-loader": "^7.1.1",
|
|
||||||
"symbol-observable": "^4.0.0",
|
|
||||||
"terser-webpack-plugin": "^5.3.1",
|
|
||||||
"ts-invariant": "^0.9.4",
|
|
||||||
"tslib": "^2.4.0",
|
|
||||||
"url": "^0.11.0",
|
|
||||||
"url-loader": "^4.1.1",
|
|
||||||
"webpack": "^5.72.0",
|
|
||||||
"webpack-bundle-analyzer": "^4.5.0",
|
|
||||||
"webpack-cli": "^4.9.2",
|
|
||||||
"webpack-dev-server": "^4.8.1",
|
|
||||||
"webpack-manifest-plugin": "^5.0.0",
|
|
||||||
"webpack-merge": "^5.8.0",
|
|
||||||
"yarn": "^1.22.18",
|
|
||||||
"zen-observable": "^0.8.15"
|
|
||||||
},
|
|
||||||
"stylelint": {
|
|
||||||
"rules": {
|
|
||||||
"block-no-empty": null,
|
|
||||||
"color-no-invalid-hex": true,
|
|
||||||
"comment-empty-line-before": [
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"ignore": [
|
|
||||||
"stylelint-commands",
|
|
||||||
"after-comment"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"declaration-colon-space-after": "always",
|
|
||||||
"indentation": [
|
|
||||||
4,
|
|
||||||
{
|
|
||||||
"except": [
|
|
||||||
"value"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"max-empty-lines": 2,
|
|
||||||
"rule-empty-line-before": [
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"except": [
|
|
||||||
"first-nested"
|
|
||||||
],
|
|
||||||
"ignore": [
|
|
||||||
"after-comment"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"unit-whitelist": [
|
|
||||||
"em",
|
|
||||||
"rem",
|
|
||||||
"%",
|
|
||||||
"s",
|
|
||||||
"px"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
11654
pnpm-lock.yaml
11654
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
3
resources/js/progressivewebapp.js
Normal file
3
resources/js/progressivewebapp.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('resources/pixelspin/silverstripe-progressivewebapp/resources/js/service-worker.js');
|
||||||
|
}
|
0
resources/js/service-worker.js
Normal file
0
resources/js/service-worker.js
Normal file
173
sass-lint.yml
173
sass-lint.yml
@ -1,173 +0,0 @@
|
|||||||
# sass-lint config to match the AirBNB style guide
|
|
||||||
files:
|
|
||||||
include: 'app/client/src/**/*.scss'
|
|
||||||
ignore:
|
|
||||||
- 'app/client/src/thirdparty/*'
|
|
||||||
options:
|
|
||||||
formatter: stylish
|
|
||||||
merge-default-rules: false
|
|
||||||
rules:
|
|
||||||
# Warnings
|
|
||||||
# Things that require actual refactoring are marked as warnings
|
|
||||||
class-name-format:
|
|
||||||
- 1
|
|
||||||
- convention: hyphenatedbem
|
|
||||||
placeholder-name-format:
|
|
||||||
- 1
|
|
||||||
- convention: hyphenatedlowercase
|
|
||||||
nesting-depth:
|
|
||||||
- 1
|
|
||||||
- max-depth: 3
|
|
||||||
no-ids: 0
|
|
||||||
no-important: 0
|
|
||||||
no-misspelled-properties:
|
|
||||||
- 1
|
|
||||||
- extra-properties:
|
|
||||||
- '-moz-border-radius-topleft'
|
|
||||||
- '-moz-border-radius-topright'
|
|
||||||
- '-moz-border-radius-bottomleft'
|
|
||||||
- '-moz-border-radius-bottomright'
|
|
||||||
variable-name-format:
|
|
||||||
- 1
|
|
||||||
- allow-leading-underscore: true
|
|
||||||
convention: hyphenatedlowercase
|
|
||||||
no-extends: 1
|
|
||||||
|
|
||||||
# Warnings: these things are preferential rather than mandatory
|
|
||||||
no-css-comments: 1
|
|
||||||
|
|
||||||
# Errors
|
|
||||||
# Things that can be easily fixed are marked as errors
|
|
||||||
indentation:
|
|
||||||
- 2
|
|
||||||
- size: 4
|
|
||||||
final-newline:
|
|
||||||
- 2
|
|
||||||
- include: true
|
|
||||||
no-trailing-whitespace: 2
|
|
||||||
border-zero:
|
|
||||||
- 2
|
|
||||||
- convention: '0'
|
|
||||||
brace-style:
|
|
||||||
- 2
|
|
||||||
- allow-single-line: true
|
|
||||||
clean-import-paths:
|
|
||||||
- 2
|
|
||||||
- filename-extension: false
|
|
||||||
- leading-underscore: true
|
|
||||||
no-debug: 2
|
|
||||||
no-empty-rulesets: 2
|
|
||||||
no-invalid-hex: 2
|
|
||||||
no-mergeable-selectors: 2
|
|
||||||
# no-qualifying-elements:
|
|
||||||
# - 1
|
|
||||||
# - allow-element-with-attribute: false
|
|
||||||
# allow-element-with-class: false
|
|
||||||
# allow-element-with-id: false
|
|
||||||
no-trailing-zero: 2
|
|
||||||
no-url-protocols: 2
|
|
||||||
quotes:
|
|
||||||
- 2
|
|
||||||
- style: double
|
|
||||||
space-after-bang:
|
|
||||||
- 2
|
|
||||||
- include: false
|
|
||||||
space-after-colon:
|
|
||||||
- 2
|
|
||||||
- include: true
|
|
||||||
space-after-comma:
|
|
||||||
- 2
|
|
||||||
- include: true
|
|
||||||
space-before-bang:
|
|
||||||
- 2
|
|
||||||
- include: true
|
|
||||||
space-before-brace:
|
|
||||||
- 2
|
|
||||||
- include: true
|
|
||||||
space-before-colon: 2
|
|
||||||
space-between-parens:
|
|
||||||
- 2
|
|
||||||
- include: false
|
|
||||||
trailing-semicolon: 2
|
|
||||||
url-quotes: 2
|
|
||||||
zero-unit: 2
|
|
||||||
single-line-per-selector: 2
|
|
||||||
one-declaration-per-line: 2
|
|
||||||
empty-line-between-blocks:
|
|
||||||
- 2
|
|
||||||
- ignore-single-line-rulesets: true
|
|
||||||
# Missing rules
|
|
||||||
# There are no sass-lint rules for the following AirBNB style items, but thess
|
|
||||||
# - Put comments on their own line
|
|
||||||
# - Put property delcarations before mixins
|
|
||||||
# Disabled rules
|
|
||||||
# These are other rules that we may wish to consider using in the future
|
|
||||||
# They are not part of the AirBNB CSS standard but they would introduce some strictness
|
|
||||||
# bem-depth: 0
|
|
||||||
# variable-for-property: 0
|
|
||||||
# no-transition-all: 0
|
|
||||||
# hex-length:
|
|
||||||
# - 1
|
|
||||||
# - style: short
|
|
||||||
# hex-notation:
|
|
||||||
# - 1
|
|
||||||
# - style: lowercase
|
|
||||||
# property-units:
|
|
||||||
# - 1
|
|
||||||
# - global:
|
|
||||||
# - ch
|
|
||||||
# - em
|
|
||||||
# - ex
|
|
||||||
# - rem
|
|
||||||
# - cm
|
|
||||||
# - in
|
|
||||||
# - mm
|
|
||||||
# - pc
|
|
||||||
# - pt
|
|
||||||
# - px
|
|
||||||
# - q
|
|
||||||
# - vh
|
|
||||||
# - vw
|
|
||||||
# - vmin
|
|
||||||
# - vmax
|
|
||||||
# - deg
|
|
||||||
# - grad
|
|
||||||
# - rad
|
|
||||||
# - turn
|
|
||||||
# - ms
|
|
||||||
# - s
|
|
||||||
# - Hz
|
|
||||||
# - kHz
|
|
||||||
# - dpi
|
|
||||||
# - dpcm
|
|
||||||
# - dppx
|
|
||||||
# - '%'
|
|
||||||
# per-property: {}
|
|
||||||
# force-attribute-nesting: 1
|
|
||||||
# force-element-nesting: 1
|
|
||||||
# force-pseudo-nesting: 1
|
|
||||||
# function-name-format:
|
|
||||||
# - 1
|
|
||||||
# - allow-leading-underscore: true
|
|
||||||
# convention: hyphenatedlowercase
|
|
||||||
# no-color-literals: 1
|
|
||||||
# no-duplicate-properties: 1
|
|
||||||
# mixin-name-format:
|
|
||||||
# - 1
|
|
||||||
# - allow-leading-underscore: true
|
|
||||||
# convention: hyphenatedlowercase
|
|
||||||
# shorthand-values:
|
|
||||||
# - 1
|
|
||||||
# - allowed-shorthands:
|
|
||||||
# - 1
|
|
||||||
# - 2
|
|
||||||
# - 3
|
|
||||||
# leading-zero:
|
|
||||||
# - 1
|
|
||||||
# - include: false
|
|
||||||
# no-vendor-prefixes:
|
|
||||||
# - 1
|
|
||||||
# - additional-identifiers: []
|
|
||||||
# excluded-identifiers: []
|
|
||||||
# placeholder-in-extend: 1
|
|
||||||
# no-color-keywords: 2
|
|
@ -1,123 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace A2nt\ProgressiveWebApp\Controllers;
|
|
||||||
|
|
||||||
use SilverStripe\Control\Controller;
|
|
||||||
use SilverStripe\Control\Director;
|
|
||||||
use SilverStripe\SiteConfig\SiteConfig;
|
|
||||||
use Site\Pages\HomePage;
|
|
||||||
|
|
||||||
class ManifestController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
private static $gcm_sender_id;
|
|
||||||
private static $background = '#000000';
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private static $allowed_actions = [
|
|
||||||
'index',
|
|
||||||
];
|
|
||||||
/**
|
|
||||||
* Default controller action for the manifest.json file
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function index($url)
|
|
||||||
{
|
|
||||||
$cfg = $this->config();
|
|
||||||
$cfg_site = SiteConfig::current_site_config();
|
|
||||||
|
|
||||||
$baseURL = Director::absoluteBaseURL();
|
|
||||||
$icons_path = self::join_links($baseURL, RESOURCES_DIR, 'app', 'client', 'dist', 'icons');
|
|
||||||
|
|
||||||
$title = $cfg_site->getField('Title');
|
|
||||||
$desc = $cfg_site->getField('Description');
|
|
||||||
$desc = $desc ?: $title;
|
|
||||||
|
|
||||||
$manifestContent = [
|
|
||||||
'lang' => 'en',
|
|
||||||
'dir' => 'ltr',
|
|
||||||
'url' => $baseURL,
|
|
||||||
'name' => $title,
|
|
||||||
'short_name' => $title,
|
|
||||||
'description' => $desc,
|
|
||||||
'offline_enabled' => true,
|
|
||||||
'start_url' => Director::baseURL(),
|
|
||||||
'scope' => Director::baseURL(),
|
|
||||||
'permissions' => [
|
|
||||||
'gcm',
|
|
||||||
],
|
|
||||||
'display' => 'standalone',
|
|
||||||
'background_color' => $cfg->get('background'),
|
|
||||||
'theme_color' => $cfg->get('background'),
|
|
||||||
'orientation' => 'portrait-primary',
|
|
||||||
'serviceworker' => [
|
|
||||||
'src' => 'sw.js?v='.ServiceWorkerController::Version(),
|
|
||||||
'scope' => '/',
|
|
||||||
'use_cache' => true,
|
|
||||||
],
|
|
||||||
'icons' => [
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'favicon-16x16.png'),
|
|
||||||
'sizes' => '16x16',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'favicon-32x32.png'),
|
|
||||||
'sizes' => '32x32',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-48x48.png'),
|
|
||||||
'sizes' => '48x48',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],[
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-72x72.png'),
|
|
||||||
'sizes' => '72x72',
|
|
||||||
'type' => 'image/png',
|
|
||||||
], [
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-96x96.png'),
|
|
||||||
'sizes' => '96x96',
|
|
||||||
'type' => 'image/png',
|
|
||||||
], [
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-144x144.png'),
|
|
||||||
'sizes' => '144x144',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-192x192.png'),
|
|
||||||
'sizes' => '192x192',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-256x256.png'),
|
|
||||||
'sizes' => '256x256',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-384x384.png'),
|
|
||||||
'sizes' => '384x384',
|
|
||||||
'type' => 'image/png',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'src' => self::join_links($icons_path, 'android-chrome-512x512.png'),
|
|
||||||
'sizes' => '512x512',
|
|
||||||
'type' => 'image/png',
|
|
||||||
'purpose' => 'any maskable',
|
|
||||||
],
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
$gcm_sender_id = $cfg->get('gcm_sender_id');
|
|
||||||
if ($gcm_sender_id) {
|
|
||||||
$manifestContent['gcm_sender_id'] = $gcm_sender_id;
|
|
||||||
$manifestContent['gcm_user_visible_only'] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getResponse()->addHeader('Content-Type', 'application/manifest+json; charset="utf-8"');
|
|
||||||
|
|
||||||
return json_encode($manifestContent);
|
|
||||||
}
|
|
||||||
}
|
|
100
src/Controllers/ProgressiveWebAppController.php
Normal file
100
src/Controllers/ProgressiveWebAppController.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pixelspin\ProgressiveWebApp\Controllers;
|
||||||
|
|
||||||
|
use SilverStripe\Control\Controller;
|
||||||
|
use SilverStripe\SiteConfig\SiteConfig;
|
||||||
|
|
||||||
|
class ProgressiveWebAppController extends Controller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $allowed_actions = [
|
||||||
|
'index'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default controller action for the manifest.json file
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function index($url) {
|
||||||
|
|
||||||
|
$config = SiteConfig::current_site_config();
|
||||||
|
$manifestContent = [];
|
||||||
|
$manifestContent['start_url'] = '/';
|
||||||
|
|
||||||
|
if($config->ManifestName){
|
||||||
|
$manifestContent['name'] = $config->ManifestName;
|
||||||
|
}
|
||||||
|
if($config->ManifestShortName){
|
||||||
|
$manifestContent['short_name'] = $config->ManifestShortName;
|
||||||
|
}
|
||||||
|
if($config->ManifestDescription){
|
||||||
|
$manifestContent['description'] = $config->ManifestDescription;
|
||||||
|
}
|
||||||
|
if($config->ManifestColor){
|
||||||
|
$manifestContent['background_color'] = $config->ManifestColor;
|
||||||
|
$manifestContent['theme_color'] = $config->ManifestColor;
|
||||||
|
}
|
||||||
|
if($config->ManifestOrientation){
|
||||||
|
$manifestContent['orientation'] = $config->ManifestOrientation;
|
||||||
|
}
|
||||||
|
if($config->ManifestDisplay){
|
||||||
|
$manifestContent['display'] = $config->ManifestDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
$logo = $config->ManifestLogo();
|
||||||
|
if($logo && $logo->exists()){
|
||||||
|
$mime = $logo->getMimeType();
|
||||||
|
$manifestContent['icons'] = [
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(48,48)->Link(),
|
||||||
|
'sizes' => '48x48',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(72,72)->Link(),
|
||||||
|
'sizes' => '72x72',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(96,96)->Link(),
|
||||||
|
'sizes' => '96x96',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(144,144)->Link(),
|
||||||
|
'sizes' => '144x144',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(168,168)->Link(),
|
||||||
|
'sizes' => '168x168',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(192,192)->Link(),
|
||||||
|
'sizes' => '192x192',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(256,256)->Link(),
|
||||||
|
'sizes' => '256x256',
|
||||||
|
'type' => $mime
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' => $logo->Fill(512,512)->Link(),
|
||||||
|
'sizes' => '512x512',
|
||||||
|
'type' => $mime
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getResponse()->addHeader('Content-Type', 'application/manifest+json; charset="utf-8"');
|
||||||
|
return json_encode($manifestContent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,108 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace A2nt\ProgressiveWebApp\Controllers;
|
|
||||||
|
|
||||||
use SilverStripe\Control\Controller;
|
|
||||||
use SilverStripe\Control\Director;
|
|
||||||
use SilverStripe\ORM\ArrayList;
|
|
||||||
use SilverStripe\View\ArrayData;
|
|
||||||
use SilverStripe\Core\ClassInfo;
|
|
||||||
use MichelSteege\ProgressiveWebApp\Interfaces\ServiceWorkerCacheProvider;
|
|
||||||
|
|
||||||
class ServiceWorkerController extends Controller {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private static $allowed_actions = [
|
|
||||||
'index',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @config
|
|
||||||
*/
|
|
||||||
private static $debug_mode = false;
|
|
||||||
private static $version = '1';
|
|
||||||
private static $custom_sw_path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default controller action for the service-worker.js file
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function index($req) {
|
|
||||||
$resp = $this->getResponse();
|
|
||||||
$script = file_get_contents(self::getScriptPath());
|
|
||||||
|
|
||||||
if($req->param('Action') === 'cachequeue') {
|
|
||||||
return json_encode([
|
|
||||||
'urls' => [
|
|
||||||
self::join_links(self::BaseUrl(),'app','client','dist', 'js', 'app.js')
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$resp->addHeader('Content-Type', 'application/javascript; charset="utf-8"');
|
|
||||||
return $this->customise([
|
|
||||||
'Script' => $script,
|
|
||||||
])->renderWith('ServiceWorker');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getScriptPath()
|
|
||||||
{
|
|
||||||
$custom_path = self::config()->get('custom_sw_path');
|
|
||||||
return $custom_path ? $custom_path : join(DIRECTORY_SEPARATOR, [
|
|
||||||
__DIR__,
|
|
||||||
'..',
|
|
||||||
'..',
|
|
||||||
'client',
|
|
||||||
'dist',
|
|
||||||
'js',
|
|
||||||
'app_sw.js',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base URL
|
|
||||||
* @return varchar
|
|
||||||
*/
|
|
||||||
public static function BaseUrl() {
|
|
||||||
return Director::absoluteBaseURL();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug mode
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function DebugMode() {
|
|
||||||
if(Director::isDev()){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return self::config()->get('debug_mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Version() {
|
|
||||||
return self::config()->get('version').filemtime(self::getScriptPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list with file to cache in the install event
|
|
||||||
* @return ArrayList
|
|
||||||
*/
|
|
||||||
public static function CacheOnInstall() {
|
|
||||||
$paths = [];
|
|
||||||
foreach(ClassInfo::implementorsOf(ServiceWorkerCacheProvider::class) as $class){
|
|
||||||
foreach($class::getServiceWorkerCachedPaths() as $path){
|
|
||||||
$paths[] = $path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$list = new ArrayList();
|
|
||||||
foreach($paths as $path){
|
|
||||||
$list->push(new ArrayData([
|
|
||||||
'Path' => $path
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace A2nt\ProgressiveWebApp\Controllers;
|
|
||||||
|
|
||||||
use SilverStripe\Control\Controller;
|
|
||||||
use SilverStripe\Control\Director;
|
|
||||||
use SilverStripe\Security\Security;
|
|
||||||
|
|
||||||
class WellKnownController extends Controller
|
|
||||||
{
|
|
||||||
private static $allowed_actions = [
|
|
||||||
'index',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
$req = $this->getRequest();
|
|
||||||
$action = $req->param('Action');
|
|
||||||
switch($action) {
|
|
||||||
case 'change-password':
|
|
||||||
return $this->changepassword();
|
|
||||||
default:
|
|
||||||
return $this->httpError(404, 'Not found');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function changepassword()
|
|
||||||
{
|
|
||||||
return $this->redirect(
|
|
||||||
Director::absoluteURL(
|
|
||||||
Security::singleton()->Link('changepassword')
|
|
||||||
), 303
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
68
src/Extensions/ProgressiveWebAppSiteConfigExtension.php
Normal file
68
src/Extensions/ProgressiveWebAppSiteConfigExtension.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pixelspin\ProgressiveWebApp\Extensions;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataExtension;
|
||||||
|
use SilverWare\Colorpicker\ORM\FieldType\DBColor;
|
||||||
|
use SilverStripe\Assets\Image;
|
||||||
|
use SilverStripe\Forms\FieldList;
|
||||||
|
use SilverStripe\AssetAdmin\Forms\UploadField;
|
||||||
|
use SilverStripe\Forms\TextField;
|
||||||
|
use SilverStripe\Forms\DropdownField;
|
||||||
|
use SilverWare\Colorpicker\Forms\ColorField;
|
||||||
|
|
||||||
|
class ProgressiveWebAppSiteConfigExtension extends DataExtension {
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'ManifestName' => 'Varchar',
|
||||||
|
'ManifestShortName' => 'Varchar',
|
||||||
|
'ManifestDescription' => 'Varchar(255)',
|
||||||
|
'ManifestColor' => DBColor::class,
|
||||||
|
'ManifestOrientation' => 'Varchar',
|
||||||
|
'ManifestDisplay' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $displays = [
|
||||||
|
'fullscreen',
|
||||||
|
'standalone',
|
||||||
|
'minimal-ui',
|
||||||
|
'browser'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $orientations = [
|
||||||
|
'any',
|
||||||
|
'natural',
|
||||||
|
'landscape',
|
||||||
|
'landscape-primary',
|
||||||
|
'landscape-secondary',
|
||||||
|
'portrait',
|
||||||
|
'portrait-primary',
|
||||||
|
'portrait-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'ManifestLogo' => Image::class
|
||||||
|
];
|
||||||
|
|
||||||
|
public function onAfterWrite() {
|
||||||
|
parent::onAfterWrite();
|
||||||
|
$manifestLogo = $this->owner->ManifestLogo();
|
||||||
|
if ($manifestLogo && $manifestLogo->exists()) {
|
||||||
|
$manifestLogo->doPublish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateCMSFields(FieldList $fields) {
|
||||||
|
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', TextField::create('ManifestName', 'Name')->setDescription('Application name'));
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', TextField::create('ManifestShortName', 'Short name')->setDescription('Short human-readable name for the application try to keep it at a maximum of 12 characters'));
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', TextField::create('ManifestDescription', 'Description')->setDescription('Short description about the app'));
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', ColorField::create('ManifestColor', 'Color')->setDescription('Color used for the splash screen and/or icon'));
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', DropdownField::create('ManifestOrientation', 'Orientation', array_combine(self::$orientations, self::$orientations))->setDescription('App orientation'));
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', DropdownField::create('ManifestDisplay', 'Display', array_combine(self::$displays, self::$displays))->setDescription('Display mode of the app'));
|
||||||
|
$fields->addFieldToTab('Root.ProgressiveWebApp', UploadField::create('ManifestLogo', 'Logo')->setDescription('This image must be square and at least 512x512px'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
namespace A2nt\ProgressiveWebApp\Extensions;
|
|
||||||
|
|
||||||
|
|
||||||
use SilverStripe\Forms\CheckboxField;
|
|
||||||
use SilverStripe\Forms\FieldList;
|
|
||||||
use SilverStripe\ORM\DataExtension;
|
|
||||||
|
|
||||||
class SiteTree extends DataExtension
|
|
||||||
{
|
|
||||||
private static $db = [
|
|
||||||
'AvailableOffline' => 'Boolean(1)',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function updateSettingsFields(FieldList $fields)
|
|
||||||
{
|
|
||||||
parent::updateCMSFields($fields);
|
|
||||||
|
|
||||||
$fields->addFieldsToTab('Root.Settings', [
|
|
||||||
CheckboxField::create('AvailableOffline', 'Make page available offline'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace A2nt\ProgressiveWebApp\Interfaces;
|
|
||||||
|
|
||||||
interface ServiceWorkerCacheProvider {
|
|
||||||
|
|
||||||
public static function getServiceWorkerCachedPaths();
|
|
||||||
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace A2nt\ProgressiveWebApp\Templates;
|
|
||||||
|
|
||||||
use A2nt\ProgressiveWebApp\Controllers\ServiceWorkerController;
|
|
||||||
use SilverStripe\View\TemplateGlobalProvider;
|
|
||||||
|
|
||||||
class ServiceWorkerTemplateProvider implements TemplateGlobalProvider
|
|
||||||
{
|
|
||||||
public static function get_template_global_variables(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'SWVersion' => 'swVersion',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function swVersion()
|
|
||||||
{
|
|
||||||
if(class_exists(ServiceWorkerController::class)) {
|
|
||||||
return ServiceWorkerController::Version();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
var version = '{$Version}',
|
|
||||||
appDomain = '{$BaseUrl}',
|
|
||||||
lang = 'en',
|
|
||||||
debug = <% if $DebugMode %>true<% else %>false<% end_if %>,
|
|
||||||
CACHE_NAME = 'sw' + version;
|
|
||||||
$Script.RAW;
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
|||||||
/*
|
|
||||||
* Common Environment
|
|
||||||
*/
|
|
||||||
|
|
||||||
const INDEX_NAME = '';
|
|
||||||
const YML_PATH = 'webpack.yml';
|
|
||||||
const CONF_VAR = 'A2nt\\CMSNiceties\\Templates\\WebpackTemplateProvider';
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
const yaml = require('js-yaml');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load webpack configuration from webpack.yml
|
|
||||||
*/
|
|
||||||
|
|
||||||
const yml = yaml.load(
|
|
||||||
fs.readFileSync(path.join(__dirname, YML_PATH), 'utf8'),
|
|
||||||
);
|
|
||||||
const conf = yml[CONF_VAR];
|
|
||||||
|
|
||||||
let themes = [];
|
|
||||||
// add themes
|
|
||||||
if (conf.THEMESDIR) {
|
|
||||||
const themeDir = conf.THEMESDIR;
|
|
||||||
const dir = path.resolve(__dirname, themeDir);
|
|
||||||
|
|
||||||
if (fs.existsSync(dir)) {
|
|
||||||
fs.readdirSync(dir).forEach((file) => {
|
|
||||||
filePath = path.join(themeDir, file);
|
|
||||||
const stat = fs.statSync(filePath);
|
|
||||||
|
|
||||||
if (stat && stat.isDirectory()) {
|
|
||||||
themes.push(filePath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup Entries */
|
|
||||||
const includes = {};
|
|
||||||
const modules = [
|
|
||||||
path.resolve(__dirname, conf.APPDIR, conf.SRC),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, conf.SRC, 'js'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, conf.SRC, 'scss'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, conf.SRC, 'img'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, conf.SRC, 'thirdparty'),
|
|
||||||
path.resolve(__dirname, 'node_modules'),
|
|
||||||
path.resolve(__dirname),
|
|
||||||
path.resolve(__dirname, 'public'),
|
|
||||||
];
|
|
||||||
|
|
||||||
const _addAppFiles = (theme) => {
|
|
||||||
const dirPath = './' + theme;
|
|
||||||
let themeName = path.basename(theme);
|
|
||||||
if (themeName == '.') {
|
|
||||||
themeName = 'app';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fs.existsSync(path.join(dirPath, conf.SRC, 'js', INDEX_NAME + '.js'))) {
|
|
||||||
includes[`${themeName}`] = path.join(dirPath, conf.SRC, 'js', INDEX_NAME + '.js');
|
|
||||||
} else if (
|
|
||||||
fs.existsSync(path.join(dirPath, conf.SRC, 'scss', INDEX_NAME + '.scss'))
|
|
||||||
) {
|
|
||||||
includes[`${themeName}`] = path.join(
|
|
||||||
dirPath,
|
|
||||||
conf.SRC,
|
|
||||||
'scss',
|
|
||||||
INDEX_NAME + '.scss',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
modules.push(path.join(dirPath, conf.SRC, 'js'));
|
|
||||||
modules.push(path.join(dirPath, conf.SRC, 'scss'));
|
|
||||||
modules.push(path.join(dirPath, conf.SRC, 'img'));
|
|
||||||
modules.push(path.join(dirPath, conf.SRC, 'thirdparty'));
|
|
||||||
|
|
||||||
const _getAllFilesFromFolder = function (dir, includeSubFolders = true) {
|
|
||||||
const dirPath = path.resolve(__dirname, dir);
|
|
||||||
let results = [];
|
|
||||||
|
|
||||||
fs.readdirSync(dirPath).forEach((file) => {
|
|
||||||
if (file.charAt(0) === '_') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = path.join(dirPath, file);
|
|
||||||
const stat = fs.statSync(filePath);
|
|
||||||
|
|
||||||
if (stat && stat.isDirectory() && includeSubFolders) {
|
|
||||||
results = results.concat(
|
|
||||||
_getAllFilesFromFolder(filePath, includeSubFolders),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
results.push(filePath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
// add page specific scripts
|
|
||||||
const typesJSPath = path.join(theme, conf.TYPESJS);
|
|
||||||
if (fs.existsSync(typesJSPath)) {
|
|
||||||
const pageScripts = _getAllFilesFromFolder(typesJSPath, true);
|
|
||||||
pageScripts.forEach((file) => {
|
|
||||||
includes[`${themeName}_${path.basename(file, '.js')}`] = file;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// add page specific scss
|
|
||||||
const typesSCSSPath = path.join(theme, conf.TYPESSCSS);
|
|
||||||
if (fs.existsSync(typesSCSSPath)) {
|
|
||||||
const scssIncludes = _getAllFilesFromFolder(typesSCSSPath, true);
|
|
||||||
scssIncludes.forEach((file) => {
|
|
||||||
includes[`${themeName}_${path.basename(file, '.scss')}`] = file;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_addAppFiles(conf.APPDIR);
|
|
||||||
|
|
||||||
// add themes
|
|
||||||
themes.forEach((theme) => {
|
|
||||||
_addAppFiles(theme);
|
|
||||||
});
|
|
||||||
|
|
||||||
const UIInfo = require('./node_modules/@a2nt/ss-bootstrap-ui-webpack-boilerplate-react/package.json');
|
|
||||||
const UIVERSION = JSON.stringify(UIInfo.version);
|
|
||||||
const UIMetaInfo = require('./node_modules/@a2nt/meta-lightbox-js/package.json');
|
|
||||||
|
|
||||||
const NODE_ENV = conf.NODE_ENV || process.env.NODE_ENV;
|
|
||||||
const COMPRESS = NODE_ENV === 'production' ? true : false;
|
|
||||||
|
|
||||||
const IP = process.env.IP || conf.HOSTNAME;
|
|
||||||
const PORT = process.env.PORT || conf.PORT;
|
|
||||||
|
|
||||||
console.log('NODE_ENV: ' + NODE_ENV);
|
|
||||||
console.log('COMPRESS: ' + COMPRESS);
|
|
||||||
console.log('WebP images: ' + conf['webp']);
|
|
||||||
console.log('GRAPHQL_API_KEY: ' + conf['GRAPHQL_API_KEY']);
|
|
||||||
|
|
||||||
const JSVARS = {
|
|
||||||
NODE_ENV: JSON.stringify(NODE_ENV),
|
|
||||||
UINAME: JSON.stringify(UIInfo.name),
|
|
||||||
UIVERSION: UIVERSION,
|
|
||||||
UIAUTHOR: JSON.stringify(UIInfo.author),
|
|
||||||
UIMetaNAME: JSON.stringify(UIMetaInfo.name),
|
|
||||||
UIMetaVersion: JSON.stringify(UIMetaInfo.version),
|
|
||||||
GRAPHQL_API_KEY: JSON.stringify(conf['GRAPHQL_API_KEY']),
|
|
||||||
SWVERSION: JSON.stringify(`sw-${new Date().getTime()}`),
|
|
||||||
BASE_HREF: JSON.stringify(''),
|
|
||||||
};
|
|
||||||
|
|
||||||
const provides = {};
|
|
||||||
const externals = {};
|
|
||||||
const aliases = {};
|
|
||||||
|
|
||||||
if (!conf['JQUERY']) {
|
|
||||||
provides['react'] = 'React';
|
|
||||||
provides['react-dom'] = 'ReactDOM';
|
|
||||||
externals['react'] = 'React';
|
|
||||||
externals['react-dom'] = 'ReactDOM';
|
|
||||||
} else {
|
|
||||||
provides['$'] = 'jquery';
|
|
||||||
provides['jQuery'] = 'jquery';
|
|
||||||
externals['jquery'] = 'jQuery';
|
|
||||||
|
|
||||||
aliases['window.jQuery'] = require.resolve('jquery');
|
|
||||||
aliases['$'] = require.resolve('jquery');
|
|
||||||
aliases['jquery'] = require.resolve('jquery');
|
|
||||||
aliases['jQuery'] = require.resolve('jquery');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
PROVIDES: provides,
|
|
||||||
JSVARS: JSVARS,
|
|
||||||
configuration: conf,
|
|
||||||
themes: themes,
|
|
||||||
webpack: {
|
|
||||||
entry: includes,
|
|
||||||
externals: externals,
|
|
||||||
resolve: {
|
|
||||||
modules: modules,
|
|
||||||
extensions: ['.tsx', '.ts', '.js'],
|
|
||||||
alias: aliases,
|
|
||||||
fallback: {
|
|
||||||
path: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
experiments: {
|
|
||||||
topLevelAwait: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,357 +0,0 @@
|
|||||||
/*
|
|
||||||
* Production assets generation
|
|
||||||
*/
|
|
||||||
const common = require('./webpack.config.common.js');
|
|
||||||
const conf = common.configuration;
|
|
||||||
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const {
|
|
||||||
merge,
|
|
||||||
} = require('webpack-merge');
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
|
|
||||||
|
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
|
||||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
|
|
||||||
//const ImageSpritePlugin = require('@a2nt/image-sprite-webpack-plugin');
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
|
|
||||||
const NODE_ENV = conf.NODE_ENV || process.env.NODE_ENV;
|
|
||||||
const COMPRESS = NODE_ENV === 'production' ? true : false;
|
|
||||||
|
|
||||||
const IP = process.env.IP || conf.HOSTNAME;
|
|
||||||
const PORT = process.env.PORT || conf.PORT;
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
new webpack.ProvidePlugin(common['PROVIDES']),
|
|
||||||
new webpack.DefinePlugin(common['JSVARS']),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
minimize: COMPRESS,
|
|
||||||
debug: !COMPRESS,
|
|
||||||
}),
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
experimentalUseImportModule: false,
|
|
||||||
filename: 'css/[name].css',
|
|
||||||
//allChunks: true,
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
const indexPath = path.join(__dirname, conf.APPDIR, conf.SRC, 'index.html');
|
|
||||||
if (fs.existsSync(indexPath)) {
|
|
||||||
plugins.push(
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
publicPath: '',
|
|
||||||
template: path.join(conf.APPDIR, conf.SRC, 'index.html'),
|
|
||||||
templateParameters: {
|
|
||||||
NODE_ENV: NODE_ENV,
|
|
||||||
GRAPHQL_URL: conf['GRAPHQL_URL'],
|
|
||||||
STATIC_URL: conf['STATIC_URL'],
|
|
||||||
REACT_SCRIPTS: NODE_ENV === 'production' ?
|
|
||||||
'<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>' : '<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script><script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>',
|
|
||||||
},
|
|
||||||
xhtml: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const faviconPath = path.join(__dirname, conf.APPDIR, conf.SRC, 'favicon.png');
|
|
||||||
if (fs.existsSync(faviconPath)) {
|
|
||||||
plugins.push(
|
|
||||||
new FaviconsWebpackPlugin({
|
|
||||||
title: 'Webpack App',
|
|
||||||
logo: faviconPath,
|
|
||||||
prefix: '/icons/',
|
|
||||||
emitStats: false,
|
|
||||||
persistentCache: true,
|
|
||||||
inject: false,
|
|
||||||
statsFilename: path.join(
|
|
||||||
conf.APPDIR,
|
|
||||||
conf.DIST,
|
|
||||||
'icons',
|
|
||||||
'iconstats.json',
|
|
||||||
),
|
|
||||||
icons: {
|
|
||||||
android: true,
|
|
||||||
appleIcon: true,
|
|
||||||
appleStartup: true,
|
|
||||||
coast: true,
|
|
||||||
favicons: true,
|
|
||||||
firefox: true,
|
|
||||||
opengraph: true,
|
|
||||||
twitter: true,
|
|
||||||
yandex: true,
|
|
||||||
windows: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add themes favicons
|
|
||||||
common.themes.forEach((theme) => {
|
|
||||||
const faviconPath = path.join(__dirname, theme, conf.SRC, 'favicon.png');
|
|
||||||
if (fs.existsSync(faviconPath)) {
|
|
||||||
plugins.push(
|
|
||||||
new FaviconsWebpackPlugin({
|
|
||||||
title: 'Webpack App',
|
|
||||||
logo: faviconPath,
|
|
||||||
prefix: '/' + theme + '-icons/',
|
|
||||||
emitStats: false,
|
|
||||||
persistentCache: true,
|
|
||||||
inject: false,
|
|
||||||
statsFilename: path.join(
|
|
||||||
conf.APPDIR,
|
|
||||||
conf.DIST,
|
|
||||||
theme + '-icons',
|
|
||||||
'iconstats.json',
|
|
||||||
),
|
|
||||||
icons: {
|
|
||||||
android: true,
|
|
||||||
appleIcon: true,
|
|
||||||
appleStartup: true,
|
|
||||||
coast: true,
|
|
||||||
favicons: true,
|
|
||||||
firefox: true,
|
|
||||||
opengraph: true,
|
|
||||||
twitter: true,
|
|
||||||
yandex: true,
|
|
||||||
windows: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const minimizers = [];
|
|
||||||
minimizers.push(
|
|
||||||
new TerserPlugin({
|
|
||||||
terserOptions: {
|
|
||||||
module: false,
|
|
||||||
parse: {
|
|
||||||
// we want terser to parse ecma 8 code. However, we don't want it
|
|
||||||
// to apply any minfication steps that turns valid ecma 5 code
|
|
||||||
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
|
||||||
// sections only apply transformations that are ecma 5 safe
|
|
||||||
// https://github.com/facebook/create-react-app/pull/4234
|
|
||||||
ecma: 8,
|
|
||||||
},
|
|
||||||
compress: {
|
|
||||||
ecma: 6,
|
|
||||||
warnings: false,
|
|
||||||
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2376
|
|
||||||
// Pending further investigation:
|
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/2011
|
|
||||||
comparisons: false,
|
|
||||||
},
|
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true,
|
|
||||||
|
|
||||||
mangle: {
|
|
||||||
safari10: true,
|
|
||||||
keep_fnames: true,
|
|
||||||
keep_classnames: true,
|
|
||||||
reserved: ['$', 'jQuery', 'jquery'],
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
ecma: 5,
|
|
||||||
comments: false,
|
|
||||||
// Turned on because emoji and regex is not minified properly using default
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2488
|
|
||||||
ascii_only: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Use multi-process parallel running to improve the build speed
|
|
||||||
// Default number of concurrent runs: os.cpus().length - 1
|
|
||||||
parallel: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (conf['PROCESS_CSS']) {
|
|
||||||
minimizers.push(
|
|
||||||
new CssMinimizerPlugin({
|
|
||||||
parallel: true,
|
|
||||||
minimizerOptions: [{
|
|
||||||
preset: [
|
|
||||||
'default',
|
|
||||||
{
|
|
||||||
discardComments: {
|
|
||||||
removeAll: true,
|
|
||||||
},
|
|
||||||
zindex: true,
|
|
||||||
cssDeclarationSorter: true,
|
|
||||||
reduceIdents: false,
|
|
||||||
mergeIdents: true,
|
|
||||||
mergeRules: true,
|
|
||||||
mergeLonghand: true,
|
|
||||||
discardUnused: true,
|
|
||||||
discardOverridden: true,
|
|
||||||
discardDuplicates: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},],
|
|
||||||
minify: [
|
|
||||||
CssMinimizerPlugin.cssnanoMinify,
|
|
||||||
//CssMinimizerPlugin.cleanCssMinify,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (COMPRESS) {
|
|
||||||
plugins.push(require('autoprefixer'));
|
|
||||||
|
|
||||||
/*plugins.push(
|
|
||||||
new ImageSpritePlugin({
|
|
||||||
exclude: /exclude|original|default-|icons|sprite|svg|logo|favicon/,
|
|
||||||
commentOrigin: false,
|
|
||||||
compress: COMPRESS,
|
|
||||||
extensions: ['png'],
|
|
||||||
indent: '',
|
|
||||||
log: true,
|
|
||||||
//outputPath: path.join(__dirname, conf.APPDIR, conf.DIST),
|
|
||||||
outputFilename: 'img/sprite-[hash].png',
|
|
||||||
padding: 0,
|
|
||||||
}),
|
|
||||||
);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
|
||||||
.BundleAnalyzerPlugin;
|
|
||||||
plugins.push(
|
|
||||||
new BundleAnalyzerPlugin({
|
|
||||||
analyzerMode: 'static',
|
|
||||||
openAnalyzer: false,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const cfg = merge(common.webpack, {
|
|
||||||
mode: NODE_ENV,
|
|
||||||
cache: {
|
|
||||||
type: 'filesystem',
|
|
||||||
},
|
|
||||||
recordsPath: path.join(__dirname, conf.APPDIR, conf.DIST, 'records.json'),
|
|
||||||
optimization: {
|
|
||||||
//removeAvailableModules: false,
|
|
||||||
//realContentHash: false,
|
|
||||||
splitChunks: {
|
|
||||||
name: 'vendor',
|
|
||||||
minChunks: 2,
|
|
||||||
},
|
|
||||||
concatenateModules: true, //ModuleConcatenationPlugin
|
|
||||||
minimizer: minimizers,
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
publicPath: path.join(conf.APPDIR, conf.DIST) + '/',
|
|
||||||
path: path.join(__dirname, conf.APPDIR, conf.DIST) + '/',
|
|
||||||
filename: path.join('js', '[name].js'),
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [{
|
|
||||||
test: /\.(js|ts)x?$/,
|
|
||||||
//exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader', //'@sucrase/webpack-loader',
|
|
||||||
options: {
|
|
||||||
//transforms: ['jsx']
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
'@babel/react',
|
|
||||||
{
|
|
||||||
plugins: [
|
|
||||||
'@babel/plugin-proposal-class-properties',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], //Preset used for env setup
|
|
||||||
plugins: [
|
|
||||||
'@babel/plugin-transform-typescript',
|
|
||||||
'@babel/transform-react-jsx',
|
|
||||||
],
|
|
||||||
cacheDirectory: true,
|
|
||||||
cacheCompression: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.s?css$/,
|
|
||||||
use: [{
|
|
||||||
loader: MiniCssExtractPlugin.loader,
|
|
||||||
options: {
|
|
||||||
publicPath: '../',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /fontawesome([^.]+).(ttf|otf|eot|woff(2)?)(\?[a-z0-9]+)?$/,
|
|
||||||
type: 'asset/resource',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(ttf|otf|eot|woff(2)?)$/,
|
|
||||||
type: 'asset/resource',
|
|
||||||
}, {
|
|
||||||
test: /\.(png|webp|jpg|jpeg|gif|svg)$/,
|
|
||||||
type: 'javascript/auto',
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'img-optimize-loader',
|
|
||||||
options: {
|
|
||||||
name: '[name].[ext]',
|
|
||||||
outputPath: 'img/',
|
|
||||||
publicPath: '../img/',
|
|
||||||
compress: {
|
|
||||||
// This will take more time and get smaller images.
|
|
||||||
mode: 'low', // 'lossless', 'high', 'low'
|
|
||||||
disableOnDevelopment: true,
|
|
||||||
webp: conf['webp'],
|
|
||||||
// loseless compression for png
|
|
||||||
optipng: {
|
|
||||||
optimizationLevel: 4,
|
|
||||||
},
|
|
||||||
// lossy compression for png. This will generate smaller file than optipng.
|
|
||||||
pngquant: {
|
|
||||||
quality: [0.2, 0.8],
|
|
||||||
},
|
|
||||||
// Compression for svg.
|
|
||||||
svgo: true,
|
|
||||||
// Compression for gif.
|
|
||||||
gifsicle: {
|
|
||||||
optimizationLevel: 3,
|
|
||||||
},
|
|
||||||
// Compression for jpg.
|
|
||||||
mozjpeg: {
|
|
||||||
progressive: true,
|
|
||||||
quality: 60,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inline: {
|
|
||||||
limit: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},],
|
|
||||||
},],
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: plugins,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(cfg);
|
|
||||||
module.exports = cfg;
|
|
@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* Development assets generation
|
|
||||||
*/
|
|
||||||
const common = require('./webpack.config.common.js');
|
|
||||||
const conf = common.configuration;
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
//const autoprefixer = require('autoprefixer');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const {
|
|
||||||
merge,
|
|
||||||
} = require('webpack-merge');
|
|
||||||
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
|
|
||||||
const IP = process.env.IP || conf.HOSTNAME;
|
|
||||||
const PORT = process.env.PORT || conf.PORT;
|
|
||||||
|
|
||||||
const NODE_ENV = 'development'; //conf.NODE_ENV || process.env.NODE_ENV;
|
|
||||||
const COMPRESS = NODE_ENV === 'production' ? true : false;
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
new webpack.ProvidePlugin(common['PROVIDES']),
|
|
||||||
new webpack.DefinePlugin(common['JSVARS']),
|
|
||||||
//new webpack.HotModuleReplacementPlugin(),
|
|
||||||
new MiniCssExtractPlugin(),
|
|
||||||
];
|
|
||||||
|
|
||||||
const indexPath = path.join(__dirname, conf.APPDIR, conf.SRC, 'index.html');
|
|
||||||
if (fs.existsSync(indexPath)) {
|
|
||||||
plugins.push(
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
publicPath: '',
|
|
||||||
template: path.join(conf.APPDIR, conf.SRC, 'index.html'),
|
|
||||||
templateParameters: {
|
|
||||||
NODE_ENV: NODE_ENV,
|
|
||||||
GRAPHQL_URL: conf['GRAPHQL_URL'],
|
|
||||||
STATIC_URL: conf['STATIC_URL'],
|
|
||||||
REACT_SCRIPTS: NODE_ENV === 'production' ?
|
|
||||||
'<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>' : '<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script><script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = merge(common.webpack, {
|
|
||||||
mode: 'development',
|
|
||||||
|
|
||||||
entry: {
|
|
||||||
/*hot: [
|
|
||||||
'react-hot-loader/patch',
|
|
||||||
'webpack-dev-server/?https://' + conf.HOSTNAME + ':' + conf.PORT,
|
|
||||||
'webpack/hot/only-dev-server',
|
|
||||||
],*/
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname),
|
|
||||||
filename: '[name].js',
|
|
||||||
// necessary for HMR to know where to load the hot update chunks
|
|
||||||
publicPath: `http${conf['HTTPS'] ? 's' : ''}://${conf['HOSTNAME']}:${
|
|
||||||
conf.PORT
|
|
||||||
}/`,
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [{
|
|
||||||
test: /\.(js|ts)x?$/,
|
|
||||||
//exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader', //'@sucrase/webpack-loader',
|
|
||||||
options: {
|
|
||||||
//transforms: ['jsx']
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
'@babel/react',
|
|
||||||
{
|
|
||||||
plugins: [
|
|
||||||
'@babel/plugin-proposal-class-properties',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], //Preset used for env setup
|
|
||||||
plugins: [
|
|
||||||
'@babel/transform-react-jsx',
|
|
||||||
'@babel/plugin-transform-typescript',
|
|
||||||
],
|
|
||||||
cacheDirectory: true,
|
|
||||||
cacheCompression: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.s?css$/,
|
|
||||||
use: [{
|
|
||||||
loader: 'style-loader', //MiniCssExtractPlugin.loader,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
},
|
|
||||||
}, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
|
|
||||||
type: 'asset/resource',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(gif|png|jpg|jpeg|ttf|otf|eot|svg|webp|woff(2)?)$/,
|
|
||||||
type: 'asset/resource',
|
|
||||||
}, ],
|
|
||||||
},
|
|
||||||
plugins: plugins,
|
|
||||||
|
|
||||||
devServer: {
|
|
||||||
host: IP,
|
|
||||||
port: PORT,
|
|
||||||
historyApiFallback: false,
|
|
||||||
static: path.resolve(__dirname, conf['APPDIR'], conf['SRC']),
|
|
||||||
https: conf['HTTPS'],
|
|
||||||
hot: false,
|
|
||||||
//injectClient: conf['injectClient'],
|
|
||||||
|
|
||||||
headers: {
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Referrer-Policy': 'unsafe-url',
|
|
||||||
'service-worker-allowed': '/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = config;
|
|
24
webpack.yml
24
webpack.yml
@ -1,24 +0,0 @@
|
|||||||
# Name: webapp-webpack
|
|
||||||
# that's important to place this file into /app/_config/webpack.yml
|
|
||||||
# with all configuration variables presented
|
|
||||||
# Cuz WebPack compiling script use it to set configuration
|
|
||||||
|
|
||||||
A2nt\CMSNiceties\Templates\WebpackTemplateProvider:
|
|
||||||
APPDIR: './'
|
|
||||||
THEMESDIR: './'
|
|
||||||
HOSTNAME: 127.0.0.1
|
|
||||||
PORT: 3000
|
|
||||||
SRC: client/src
|
|
||||||
DIST: client/dist
|
|
||||||
TYPESJS: client/src/js/types
|
|
||||||
TYPESSCSS: client/src/scss/types
|
|
||||||
webp: false
|
|
||||||
NODE_ENV: production #production,development
|
|
||||||
HTTPS: true
|
|
||||||
injectClient: true
|
|
||||||
GRAPHQL_URL: '/graphql'
|
|
||||||
GRAPHQL_API_KEY: 'hGz2hB26Sse2ageAsLD6xUD1WPPfZJyI5IfI7o'
|
|
||||||
PROCESS_CSS: true # Deep CSS minification
|
|
||||||
absolute_path: false
|
|
||||||
JQUERY: false # We don't use jQuery, otherwise it's aliassed and being loaded externaly
|
|
||||||
#STATIC_URL: 'http://127.0.0.1'
|
|
Loading…
Reference in New Issue
Block a user