building css with webpack

This commit is contained in:
antelle 2019-08-16 18:45:11 +02:00
parent 32b4e99c12
commit a7096b5cdf
9 changed files with 485 additions and 691 deletions

View File

@ -1,11 +1,9 @@
/* eslint-env node */
const fs = require('fs');
const sass = require('node-sass');
const path = require('path');
const webpackConfig = require('./webpack.config');
const postCssReplaceFont = require('./build/util/postcss-replace-font');
const pkg = require('./package.json');
module.exports = function(grunt) {
@ -148,30 +146,6 @@ module.exports = function(grunt) {
desktop: ['desktop/**/*.js', '!desktop/node_modules/**'],
grunt: ['Gruntfile.js', 'grunt/**/*.js']
},
sass: {
options: {
sourceMap: false,
includePaths: ['./node_modules'],
implementation: sass
},
dist: {
files: {
'tmp/css/main.css': 'app/styles/main.scss'
}
}
},
postcss: {
options: {
processors: [
postCssReplaceFont,
require('cssnano')({discardComments: {removeAll: true}})
]
},
dist: {
src: 'tmp/css/main.css',
dest: 'tmp/css/main.css'
}
},
inline: {
app: {
src: 'tmp/index.html',
@ -222,8 +196,9 @@ module.exports = function(grunt) {
},
'webpack-dev-server': {
options: {
webpack: webpackConfig.devServerConfig(grunt),
publicPath: '/tmp/js',
webpack: webpackConfig.config(grunt, 'development'),
publicPath: '/',
contentBase: path.resolve(__dirname, 'tmp'),
progress: false
},
js: {
@ -251,10 +226,6 @@ module.exports = function(grunt) {
interrupt: true,
debounceDelay: 500
},
styles: {
files: 'app/styles/**/*.scss',
tasks: ['sass']
},
indexhtml: {
files: 'app/index.html',
tasks: ['copy:html']
@ -549,15 +520,6 @@ module.exports = function(grunt) {
}
}
},
'concurrent': {
options: {
logConcurrentOutput: true
},
'dev-server': [
'watch:styles',
'webpack-dev-server'
]
},
'sign-dist': {
'dist': {
options: {

View File

@ -26,7 +26,7 @@
<link rel="apple-touch-startup-image" href="icons/splash-1668x2224.png" media="(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-2048x2732.png" media="(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="css/main.css?__inline=true" />
<link rel="stylesheet" href="css/app.css?__inline=true" />
<script src="js/vendor.js?__inline=true"></script>
<script src="js/app.js?__inline=true"></script>
<script src="js/runtime.js?__inline=true"></script>

View File

@ -1,7 +1,9 @@
@import "../node_modules/normalize.css/normalize";
@import "../node_modules/font-awesome/scss/font-awesome";
@import "../node_modules/pikaday/scss/pikaday";
@import "../node_modules/bourbon/app/assets/stylesheets/bourbon";
$fa-font-path: '~font-awesome/fonts';
@import "~normalize.css/normalize";
@import "~font-awesome/scss/font-awesome";
@import "~pikaday/scss/pikaday";
@import "~bourbon/app/assets/stylesheets/bourbon";
@import "themes/all-themes";

View File

@ -1,25 +0,0 @@
const fs = require('fs');
function replaceFont(css) {
css.walkAtRules('font-face', rule => {
const fontFamily = rule.nodes.filter(n => n.prop === 'font-family')[0];
if (!fontFamily) {
throw 'Bad font rule: ' + rule.toString();
}
const value = fontFamily.value.replace(/["']/g, '');
const fontFiles = {
FontAwesome: 'fontawesome-webfont.woff'
};
const fontFile = fontFiles[value];
if (!fontFile) {
throw 'Unsupported font ' + value + ': ' + rule.toString();
}
const data = fs.readFileSync('tmp/fonts/' + fontFile, 'base64');
const src = 'url(data:application/font-woff;charset=utf-8;base64,{data}) format(\'woff\')'
.replace('{data}', data);
rule.nodes = rule.nodes.filter(n => n.prop !== 'src');
rule.append({ prop: 'src', value: src });
});
}
module.exports = replaceFont;

View File

@ -10,7 +10,7 @@ module.exports = function(grunt) {
]);
grunt.registerTask('devsrv', 'Start web server and watcher', [
'concurrent:dev-server'
'webpack-dev-server'
]);
grunt.registerTask('desktop', 'Build web and desktop apps for all platforms', [

View File

@ -10,8 +10,6 @@ module.exports = function(grunt) {
'copy:fonts',
'webpack',
'uglify',
'sass',
'postcss',
'inline',
'htmlmin',
'string-replace:manifest-html',

993
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,6 @@
"baron": "2.2.2",
"base64-loader": "1.0.0",
"bourbon": "4.2.7",
"cssnano": "4.1.8",
"electron": "^4.0.1",
"eslint": "^5.12.0",
"eslint-config-standard": "12.0.0",
@ -29,7 +28,6 @@
"exports-loader": "0.7.0",
"font-awesome": "4.7.0",
"grunt": "1.0.3",
"grunt-concurrent": "2.3.1",
"grunt-contrib-clean": "2.0.0",
"grunt-contrib-compress": "1.4.3",
"grunt-contrib-copy": "1.0.0",
@ -41,24 +39,25 @@
"grunt-eslint": "21.0.0",
"grunt-gitinfo": "github:keeweb/grunt-gitinfo#b61aaed",
"grunt-inline-alt": "github:keeweb/grunt-inline-alt#ec9f6ad",
"grunt-postcss": "0.9.0",
"grunt-sass": "3.0.2",
"grunt-string-replace": "1.3.1",
"grunt-webpack": "3.1.3",
"handlebars": "4.0.12",
"handlebars-loader": "1.7.1",
"html-minifier": "3.5.21",
"ignore-loader": "^0.1.2",
"jquery": "3.3.1",
"json-loader": "^0.5.4",
"jsqrcode": "github:antelle/jsqrcode#0.1.3",
"kdbxweb": "1.2.7",
"load-grunt-tasks": "4.0.0",
"node-sass": "^4.12.0",
"mini-css-extract-plugin": "^0.8.0",
"node-stream-zip": "1.7.0",
"normalize.css": "8.0.1",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"pikaday": "1.8.0",
"pkcs15-smartcard-sign": "^1.0.0",
"raw-loader": "1.0.0",
"raw-loader": "^1.0.0",
"sass-loader": "^7.2.0",
"stats-webpack-plugin": "0.7.0",
"string-replace-webpack-plugin": "0.1.3",
"strip-sourcemap-loader": "0.0.1",
@ -66,6 +65,7 @@
"time-grunt": "2.0.0",
"uglify-loader": "3.0.0",
"uglifyjs-webpack-plugin": "^2.1.1",
"url-loader": "^2.1.0",
"webpack": "^4.28.3",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-dev-server": "^3.1.14"

View File

@ -5,23 +5,28 @@ const webpack = require('webpack');
const StringReplacePlugin = require('string-replace-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const pkg = require('./package.json');
function config(grunt) {
process.noDeprecation = true; // for css loaders
function config(grunt, mode = 'production') {
const devMode = mode === 'development';
const date = grunt.config.get('date');
const dt = date.toISOString().replace(/T.*/, '');
const year = date.getFullYear();
return {
mode: 'production',
mode,
entry: {
app: 'app',
app: ['app', 'main.scss'],
vendor: ['jquery', 'underscore', 'backbone', 'kdbxweb', 'baron',
'pikaday', 'jsqrcode', 'argon2-wasm', 'argon2']
},
output: {
path: path.resolve('.', 'tmp/js'),
filename: '[name].js'
path: path.resolve('.', 'tmp'),
filename: 'js/[name].js'
},
target: 'web',
performance: {
@ -35,16 +40,19 @@ function config(grunt) {
progress: false,
failOnError: true,
resolve: {
modules: [path.join(__dirname, 'app/scripts'), path.join(__dirname, 'node_modules')],
modules: [
path.join(__dirname, 'app/scripts'),
path.join(__dirname, 'app/styles'),
path.join(__dirname, 'node_modules')
],
alias: {
backbone: 'backbone/backbone-min.js',
underscore: 'underscore/underscore-min.js',
_: 'underscore/underscore-min.js',
jquery: 'jquery/dist/jquery.min.js',
backbone: `backbone/backbone${devMode ? '-min' : ''}.js`,
underscore: `underscore/underscore${devMode ? '-min' : ''}.js`,
_: `underscore/underscore${devMode ? '-min' : ''}.js`,
jquery: `jquery/dist/jquery${devMode ? '.min' : ''}.js`,
kdbxweb: 'kdbxweb/dist/kdbxweb.js',
baron: 'baron/baron.min.js',
pikaday: 'pikaday/pikaday.js',
qrcode: 'jsqrcode/dist/qrcode.min.js',
baron: `baron/baron${devMode ? '.min' : ''}.js`,
qrcode: `jsqrcode/dist/qrcode${devMode ? '.min' : ''}.js`,
argon2: 'argon2-browser/dist/argon2.min.js',
hbs: 'handlebars/runtime.js',
'argon2-wasm': 'argon2-browser/dist/argon2.wasm',
@ -77,7 +85,19 @@ function config(grunt) {
},
{test: /argon2\.wasm/, type: 'javascript/auto', loader: 'base64-loader'},
{test: /argon2(\.min)?\.js/, loader: 'raw-loader'},
{test: /\.scss$/, loader: 'raw-loader'}
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { sourceMap: devMode } },
{ loader: 'sass-loader', options: { sourceMap: devMode } }
]
},
{
test: /fonts\/.*\.(woff2|ttf|eot|svg)/,
use: ['raw-loader', 'ignore-loader']
},
{ test: /\.woff$/, loader: 'url-loader' }
]
},
optimization: {
@ -96,12 +116,17 @@ function config(grunt) {
cache: true,
parallel: true
}),
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }]
}
}),
new BundleAnalyzerPlugin({
openAnalyzer: false,
analyzerMode: 'static',
reportFilename: '../stats/analyzer_report.html',
reportFilename: 'stats/analyzer_report.html',
generateStatsFile: true,
statsFilename: '../stats/stats.json'
statsFilename: 'stats/stats.json'
})
]
},
@ -110,7 +135,10 @@ function config(grunt) {
', opensource.org/licenses/' + pkg.license),
new webpack.ProvidePlugin({_: 'underscore', $: 'jquery'}),
new webpack.IgnorePlugin(/^(moment)$/),
new StringReplacePlugin()
new StringReplacePlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].css'
})
],
node: {
console: false,
@ -128,27 +156,9 @@ function config(grunt) {
crypto: 'null',
fs: 'null',
path: 'null'
}
},
devtool: devMode ? 'source-map' : undefined
};
}
function devServerConfig(grunt) {
const devServerConfig = config(grunt);
Object.assign(devServerConfig, {
mode: 'development',
devtool: 'source-map'
});
Object.assign(devServerConfig.resolve.alias, {
backbone: 'backbone/backbone.js',
underscore: 'underscore/underscore.js',
_: 'underscore/underscore.js',
jquery: 'jquery/dist/jquery.js',
baron: 'baron/baron.js',
qrcode: 'jsqrcode/dist/qrcode.js',
argon2: 'argon2-browser/dist/argon2.js'
});
return devServerConfig;
}
module.exports.config = config;
module.exports.devServerConfig = devServerConfig;