Build system update

This commit is contained in:
Tony Air 2020-11-28 18:38:07 +07:00
parent 80b0acf887
commit d2c610b3d1
8 changed files with 12605 additions and 132 deletions

1
.npmrc
View File

@ -1 +1,2 @@
registry=https://npm.pkg.github.com/a2nt
registry=https://registry.npmjs.org/

1
client/dist/js/app.js vendored Normal file
View File

@ -0,0 +1 @@
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/mnt/data/srv/dist/repositories/silverstripe-progressivewebapp/client/dist",r(r.s="./client/src/js/app.js")}({"./client/src/js/app.js":function(e,t){if("serviceWorker"in navigator){var r=(document.getElementsByTagName("base")[0]||{}).href,n=(document.querySelector('meta[name="swversion"]')||{}).content;r&&navigator.serviceWorker.register("".concat(r,"sw.js?v=").concat(n)).then((function(){console.log("SW: Registered")}))}}});

1
client/dist/js/sw.js vendored Normal file
View File

@ -0,0 +1 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/mnt/data/srv/dist/repositories/silverstripe-progressivewebapp/client/dist",n(n.s="./client/src/js/sw.js")}({"./client/src/js/sw.js":function(e,t,n){var r=n("./client/src/lib/log.js"),o=n("./client/src/thirdparty/serviceworker-caches.js");if(debug&&(r("SW: debug is on"),r("SW: CACHE_NAME: ".concat(CACHE_NAME)),r("SW: appDomain: ".concat(appDomain)),r("SW: lang: ".concat(lang))),"string"!==typeof self.CACHE_NAME)throw new Error("Cache Name cannot be empty");self.addEventListener("fetch",(function(e){if("GET"===e.request.method){var t=new URL(e.request.url);if(t.pathname.indexOf("admin")>=0||t.pathname.indexOf("Security")>=0||t.pathname.indexOf("dev")>=0)r("SW: skip admin ".concat(e.request.url));else{var n=e.request.clone(),i=e.request.clone();e.respondWith(fetch(n).then((function(t){var n=t.clone();return o.open(self.CACHE_NAME).then((function(t){var r=e.request.clone();t.put(r,n)})),t})).catch((function(e){return r("SW: fetch failed"),o.match(i)})))}}})),self.addEventListener("activate",(function(e){r("SW: activated: ".concat(version)),e.waitUntil(o.delete(self.CACHE_NAME))})),self.addEventListener("install",(function(e){r("SW: installing version: ".concat(version))}))},"./client/src/lib/log.js":function(e,t){e.exports=function(e){debug&&console.log(e)}},"./client/src/thirdparty/serviceworker-caches.js":function(e,t){Cache.prototype.add||(Cache.prototype.add=function(e){return this.addAll([e])}),Cache.prototype.addAll||(Cache.prototype.addAll=function(e){var t=this;function n(e){this.name="NetworkError",this.code=19,this.message=e}return n.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 n("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(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}});

View File

@ -1,6 +1,6 @@
// caches polyfill because it is not added to native yet!
var log = require('./lib/log');
var caches = require('./thirdparty/serviceworker-caches');
var log = require('../lib/log');
var caches = require('../thirdparty/serviceworker-caches');
if (debug) {
log('SW: debug is on');
@ -34,7 +34,7 @@ self.addEventListener('fetch', (event) => {
requestURL.pathname.indexOf('Security') >= 0 ||
requestURL.pathname.indexOf('dev') >= 0
) {
log(`SW: skip admin ${ event.request.url}`);
log(`SW: skip admin ${event.request.url}`);
return;
}

95
package.json Executable file → Normal file
View File

@ -8,7 +8,7 @@
"main": "client/src/app.js",
"repository": {
"type": "git",
"url": "git+https://github.com/a2nt/webpack-bootstrap-ui-kit"
"url": "git+https://github.com/a2nt/silverstripe-progressivewebapp.git"
},
"engines": {
"yarn": ">= 1.0.0"
@ -17,39 +17,84 @@
"start": "cross-env NODE_ENV=development webpack-dev-server --https -d --config webpack.config.js",
"dash": "cross-env NODE_ENV=development webpack-dashboard -- webpack-dev-server --config webpack.config.js",
"build": "cross-env NODE_ENV=production webpack -p --config webpack.config.js --progress",
"lint:check": "eslint ./client/src --config .eslintrc",
"lint:fix": "eslint ./client/src --config .eslintrc --fix",
"lint:check": "eslint ./client/src --config .eslintrc && sass-lint ./client/src --config .sasslintrc -v -q",
"lint:fix": "eslint ./client/src --config .eslintrc --fix && sass-lint ./client/src --config .sasslintrc -v -q --fix",
"lint:js": "eslint ./client/src --config .eslintrc",
"prebuild": "yarn lint:fix && rimraf ./client/dist",
"lint:sass": "sass-lint ./client/src --config .sasslintrc -v -q",
"prebuild": "yarn lint:fix && rimraf dist",
"prepare": "yarn lint:fix && yarn build",
"prunecaches": "rimraf ./node_modules/.cache/",
"postinstall": "npm run prunecaches",
"postuninstall": "npm run prunecaches"
},
"dependencies": {
"yarn": "^1.22.4"
},
"devDependencies": {
"babel-loader": "*",
"@babel/preset-env": "*",
"babel-eslint": "^8.2.6",
"rimraf": "^2.6.3",
"terser-webpack-plugin": "^2.3.5",
"url-loader": "^0.6.2",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^1.3.2",
"webpack-merge": "^4.1.1",
"hard-source-webpack-plugin": "^0.13.1"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com/"
"postuninstall": "npm run prunecaches",
"preinstall": "npx only-allow pnpm"
},
"browserslist": [
"defaults",
"ie>=11"
],
"dependencies": {
"jquery": "^3.5.1",
"yarn": "^1.22.10"
},
"devDependencies": {
"@a2nt/image-sprite-webpack-plugin": "^0.2.5",
"@babel/core": "^7.12.3",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/plugin-transform-react-jsx": "^7.12.5",
"@babel/preset-env": "^7.12.1",
"@google/markerclusterer": "^2.0.9",
"animate.css": "^4.1.1",
"ansi-html": "^0.0.7",
"ansi-regex": "^5.0.0",
"autoprefixer": "^9.8.6",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"copy-webpack-plugin": "^6.3.0",
"croppie": "^2.6.5",
"cross-env": "^7.0.2",
"css-loader": "^4.3.0",
"eslint": "^7.12.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jquery": "^1.5.1",
"eslint-plugin-react": "^7.21.5",
"exports-loader": "^1.1.1",
"favicons-webpack-plugin": "4.2.0",
"file-loader": "^6.2.0",
"font-awesome": "^4.7.0",
"hard-source-webpack-plugin": "^0.13.1",
"html-entities": "^1.3.1",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^4.5.0",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^8.0.0",
"imagemin-webpack": "^5.1.1",
"loglevel": "^1.7.0",
"mini-css-extract-plugin": "^0.11.3",
"node-sass": "^4.14.1",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^4.0.4",
"react-hot-loader": "^4.13.0",
"resolve-url-loader": "^3.1.2",
"rimraf": "^3.0.2",
"routie": "0.0.1",
"sass-lint": "^1.13.1",
"sass-lint-fix": "^1.12.1",
"sass-loader": "^10.0.5",
"script-ext-html-webpack-plugin": "^2.1.5",
"sockjs-client": "^1.5.0",
"strip-ansi": "^6.0.0",
"style-loader": "^1.3.0",
"svg-url-loader": "^6.0.0",
"terser-webpack-plugin": "^4.2.3",
"url-loader": "^4.1.1",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-manifest-plugin": "^2.2.0",
"webpack-merge": "^5.3.0"
},
"stylelint": {
"rules": {
"block-no-empty": null,

12180
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,123 +1,368 @@
const SOURCEDIR = './src';
const SOURCEDIR = './client/src';
const DISTDIR = './client/dist';
const COMPRESS = true;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
const filesystem = require('fs');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack');
const ImageSpritePlugin = require('@a2nt/image-sprite-webpack-plugin');
const UIInfo = require('./package.json');
const plugins = [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
new HardSourceWebpackPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: COMPRESS,
debug: false,
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
new HardSourceWebpackPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: COMPRESS,
debug: false,
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
allChunks: true,
}),
/**/
/*new HtmlWebpackPlugin({
template: SOURCEDIR + '/index.html',
}),*/
new webpack.DefinePlugin({
UINAME: JSON.stringify(UIInfo.name),
UIVERSION: JSON.stringify(UIInfo.version),
UIAUTHOR: JSON.stringify(UIInfo.author),
}),
];
const dirPath = path.resolve(__dirname, 'client/src/');
const includes = {
app: path.join(dirPath, 'app.js'),
sw: path.join(dirPath, 'sw.js'),
if (COMPRESS) {
plugins.push(
new OptimizeCssAssetsPlugin({
//assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default'],
},
cssProcessorOptions: {
zindex: true,
cssDeclarationSorter: true,
reduceIdents: false,
mergeIdents: true,
mergeRules: true,
mergeLonghand: true,
discardUnused: true,
discardOverridden: true,
discardDuplicates: true,
discardComments: {
removeAll: true,
},
},
canPrint: true,
}),
);
plugins.push(require('autoprefixer'));
plugins.push(
new ImageminPlugin({
bail: false, // Ignore errors on corrupted images
cache: true,
filter: (source, sourcePath) => {
if (source.byteLength < 512000) {
return false;
}
return true;
},
imageminOptions: {
plugins: [
['gifsicle', { interlaced: true }],
['jpegtran', { progressive: true }],
['optipng', { optimizationLevel: 5 }],
[
'svgo',
{
plugins: [
{
removeViewBox: false,
},
],
},
],
],
},
}),
);
plugins.push(
new ImageSpritePlugin({
exclude: /exclude|original|default-|icons|sprite/,
commentOrigin: false,
compress: true,
extensions: ['png'],
indent: '',
log: true,
//outputPath: path.join(__dirname, conf.APPDIR, conf.DIST),
outputFilename: 'img/sprite-[hash].png',
padding: 0,
}),
);
}
const includes = {};
const _addAppFiles = (theme) => {
const dirPath = path.resolve(__dirname, theme);
const themeName = path.basename(theme);
if (filesystem.existsSync(path.join(dirPath, 'js', 'app.js'))) {
includes['app'] = path.join(dirPath, 'js', 'app.js');
} else if (filesystem.existsSync(path.join(dirPath, 'scss', 'app.scss'))) {
includes['app'] = path.join(dirPath, 'scss', 'app.scss');
}
includes['sw'] = path.join(dirPath, 'js', 'sw.js');
const _getAllFilesFromFolder = function (dir, includeSubFolders = true) {
const dirPath = path.resolve(__dirname, dir);
let results = [];
filesystem.readdirSync(dirPath).forEach((file) => {
if (file.charAt(0) === '_') {
return;
}
const filePath = path.join(dirPath, file);
const stat = filesystem.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, 'js/types');
if (filesystem.existsSync(typesJSPath)) {
const pageScripts = _getAllFilesFromFolder(typesJSPath, true);
pageScripts.forEach((file) => {
includes[`app_${path.basename(file, '.js')}`] = file;
});
}
// add page specific scss
const typesSCSSPath = path.join(theme, 'scss/types');
if (filesystem.existsSync(typesSCSSPath)) {
const scssIncludes = _getAllFilesFromFolder(typesSCSSPath, true);
scssIncludes.forEach((file) => {
includes[`app_${path.basename(file, '.scss')}`] = file;
});
}
};
_addAppFiles(SOURCEDIR);
module.exports = {
entry: includes,
output: {
path: path.resolve(__dirname, 'client', 'dist'),
filename: path.join('[name].js'),
publicPath: path.resolve(__dirname, 'client', 'dist'),
},
devtool: COMPRESS ? '' : 'source-map',
externals: {},
optimization: {
namedModules: true,
splitChunks: {
name: 'vendor',
minChunks: 2,
},
noEmitOnErrors: true,
concatenateModules: true,
minimizer: COMPRESS
? [
new TerserPlugin({
terserOptions: {
parse: {
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
comparisons: false,
},
mangle: {
safari10: true,
},
output: {
ecma: 5,
comments: false,
ascii_only: true,
},
},
parallel: true,
cache: true,
}),
]
: [],
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true,
cacheCompression: false,
},
},
entry: includes,
output: {
path: path.resolve(__dirname, DISTDIR),
filename: path.join('js', '[name].js'),
publicPath: path.resolve(__dirname, DISTDIR),
},
devtool: COMPRESS ? '' : 'source-map',
externals: {
jquery: 'jQuery',
},
optimization: {
namedModules: true, // NamedModulesPlugin()
splitChunks: {
// CommonsChunkPlugin()
name: 'vendor',
minChunks: 2,
},
noEmitOnErrors: true, // NoEmitOnErrorsPlugin
concatenateModules: true, //ModuleConcatenationPlugin
minimizer: [
new TerserPlugin({
terserOptions: {
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: 5,
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,
},
mangle: {
safari10: true,
},
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,
// Enable file caching
cache: true,
}),
],
},
module: {
rules: [
{
test: /\.jsx?$/,
//exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'], //Preset used for env setup
plugins: [
['@babel/transform-react-jsx'],
['react-hot-loader/babel'],
],
cacheDirectory: true,
cacheCompression: false,
},
},
},
/*{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
},
},
],
},
resolve: {
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules'),
],
},
plugins: plugins,
test: /\.coffee?$/,
use: 'coffee-loader',
},*/
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
},
},
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: !COMPRESS,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: !COMPRESS,
},
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: {
sourceMap: !COMPRESS,
},
},
],
},
{
test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/',
publicPath: '../fonts/',
},
},
],
},
{
test: /\.(ttf|otf|eot|svg|woff(2)?)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/',
publicPath: '../fonts/',
},
},
],
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'img/',
publicPath: '../img/',
},
},
],
},
resolve: {
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules'),
],
alias: {
jquery: require.resolve('jquery'),
jQuery: require.resolve('jquery'),
},
},
plugins: plugins,
devServer: {
host: '127.0.0.1',
port: 8001,
historyApiFallback: true,
hot: false,
clientLogLevel: 'info',
contentBase: [
path.resolve(__dirname, 'client/src'),
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, 'client/dist'),
],
//watchContentBase: true,
overlay: {
warnings: true,
errors: true,
},
headers: {
'Access-Control-Allow-Origin': '*',
},
},
devServer: {
host: '127.0.0.1',
port: 8001,
historyApiFallback: true,
hot: false,
clientLogLevel: 'info',
contentBase: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, 'dist'),
],
//watchContentBase: true,
overlay: {
warnings: true,
errors: true,
},
headers: {
'Access-Control-Allow-Origin': '*',
},
},
};