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.0" have entirely different histories.
@ -1,8 +1,6 @@
|
||||
# For more information about the properties used in
|
||||
# this file, please see the EditorConfig documentation:
|
||||
# http://editorconfig.org/
|
||||
|
||||
root = true
|
||||
# For more information about the properties used in this file,
|
||||
# please see the EditorConfig documentation:
|
||||
# http://editorconfig.org
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
@ -12,15 +10,8 @@ indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.yml]
|
||||
[{*.yml,package.json,*.scss,*.js}]
|
||||
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
|
||||
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
|
||||
/yarn.lock
|
||||
yarn-error\.log
|
||||
/node_modules/
|
||||
/**/*.js.map
|
||||
/**/*.css.map
|
||||
|
2
.npmrc
2
.npmrc
@ -1,2 +0,0 @@
|
||||
registry=https://npm.pkg.github.com/a2nt
|
||||
registry=https://registry.npmjs.org/
|
27
README.md
27
README.md
@ -1,33 +1,12 @@
|
||||
# SilverStripe Progressive Web App
|
||||
|
||||
Tools to add progressive web app functionality to your silverstripe website
|
||||
And make it available offline
|
||||
|
||||
## Installation
|
||||
```
|
||||
composer require a2nt/silverstripe-progressivewebapp
|
||||
composer require pixelspin/silverstripe-progressivewebapp
|
||||
```
|
||||
|
||||
## Usage
|
||||
- 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)
|
||||
```
|
||||
if ('serviceWorker' in navigator) {
|
||||
var baseHref = (document.getElementsByTagName('base')[0] || {}).href;
|
||||
var version = (document.querySelector('meta[name="swversion"]') || {})
|
||||
.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}" />
|
||||
```
|
||||
Install the module, run dev/build and fill in the settings in the siteconfig
|
||||
Place the link to the manifest file (<link rel="manifest" href="{$BaseHref}manifest.json">) in the head of your pages
|
@ -1 +0,0 @@
|
||||
<?php
|
@ -4,10 +4,8 @@ Name: progressivewebapp
|
||||
|
||||
SilverStripe\Control\Director:
|
||||
rules:
|
||||
'manifest.json': 'A2nt\ProgressiveWebApp\Controllers\ManifestController'
|
||||
'sw.js/$Action': 'A2nt\ProgressiveWebApp\Controllers\ServiceWorkerController'
|
||||
'.well-known/$Action!': 'A2nt\ProgressiveWebApp\Controllers\WellKnownController'
|
||||
'manifest.json': 'Pixelspin\ProgressiveWebApp\Controllers\ProgressiveWebAppController'
|
||||
|
||||
SilverStripe\CMS\Model\SiteTree:
|
||||
SilverStripe\SiteConfig\SiteConfig:
|
||||
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",
|
||||
"description": "Tools to add offline caching and the other progressive web app functionality to your silverstripe website",
|
||||
"name": "pixelspin/silverstripe-progressivewebapp",
|
||||
"description": "Tools to add progressive web app functionality to your silverstripe website",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"keywords": [
|
||||
"silverstripe",
|
||||
@ -8,29 +8,30 @@
|
||||
"app"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tony Air",
|
||||
"email": "tony@twma.pro"
|
||||
"authors": [{
|
||||
"name": "Michel van der Steege",
|
||||
"email": "michelsteege@hotmail.com"
|
||||
}],
|
||||
"minimum-stability": "dev",
|
||||
"require":
|
||||
{
|
||||
"silverstripe/cms": "*"
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"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",
|
||||
"branch-alias":
|
||||
{
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload":
|
||||
{
|
||||
"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
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);
|
||||
}
|
||||
}
|
90
src/Controllers/ProgressiveWebAppController.php
Normal file
90
src/Controllers/ProgressiveWebAppController.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?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
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
$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'));
|
||||
$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