Verified Commit ee872c44 authored by FabioWidmer's avatar FabioWidmer
Browse files

Improve SEO

parent ae20fe50
......@@ -6,31 +6,31 @@ const config = require('./webpack.config.js');
const env = process.env.NODE_ENV || 'development';
const target = process.env.TARGET || 'web';
const isCordova = target === 'cordova'
const isCordova = target === 'cordova';
const spinner = ora(env === 'production' ? 'building for production...' : 'building development version...');
spinner.start();
rm(isCordova ? './cordova/www' : './www/', (removeErr) => {
if (removeErr) throw removeErr;
if(removeErr) throw removeErr;
webpack(config, (err, stats) => {
if (err) throw err;
spinner.stop();
webpack(config, (err, stats) => {
if(err) throw err;
spinner.stop();
process.stdout.write(`${stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false,
})}\n\n`);
process.stdout.write(`${stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false,
})}\n\n`);
if (stats.hasErrors()) {
console.log(chalk.red('Build failed with errors.\n'));
process.exit(1);
}
if(stats.hasErrors()) {
console.log(chalk.red('Build failed with errors.\n'));
process.exit(1);
}
console.log(chalk.cyan('Build complete.\n'));
});
console.log(chalk.cyan('Build complete.\n'));
});
});
......@@ -10,212 +10,232 @@ const WorkboxPlugin = require('workbox-webpack-plugin');
const path = require('path');
function resolvePath(dir) {
return path.join(__dirname, '..', dir);
return path.join(__dirname, '..', dir);
}
const env = process.env.NODE_ENV || 'development';
const target = process.env.TARGET || 'web';
const isCordova = target === 'cordova';
const isElectronWatch = process.env.ELECTRON_WATCH || false;
const hashName = env === 'production' ? '.[hash:8]' : '';
module.exports = {
mode: env,
entry: {
app: './src/js/app.js',
},
output: {
path: resolvePath(isCordova ? (isElectronWatch ? 'cordova/platforms/electron/www' : 'cordova/www') : 'www'),
filename: 'js/[name].js',
chunkFilename: 'js/[name].js',
publicPath: '',
hotUpdateChunkFilename: 'hot/hot-update.js',
hotUpdateMainFilename: 'hot/hot-update.json',
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
vue$: 'vue/dist/vue.esm.js',
'@': resolvePath('src'),
},
mode: env,
entry: {
app: './src/js/app.js',
},
output: {
path: resolvePath(isCordova ? (isElectronWatch ? 'cordova/platforms/electron/www' : 'cordova/www') : 'www'),
filename: `js/[name]${hashName}.js`,
chunkFilename: `js/[name]${hashName}.js`,
publicPath: '',
hotUpdateChunkFilename: 'hot/hot-update.js',
hotUpdateMainFilename: 'hot/hot-update.json',
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
vue$: 'vue/dist/vue.esm.js',
'@': resolvePath('src'),
},
},
devtool: env === 'production' ? 'source-map' : 'eval',
devServer: {
hot: false, //Changed
open: true,
compress: true,
contentBase: '/www/',
disableHostCheck: true,
historyApiFallback: true,
watchOptions: {
poll: 1000,
},
},
optimization: {
minimizer: [new TerserPlugin({
sourceMap: true,
})],
},
module: {
rules: [
{
test: /\.(mjs|js|jsx)$/,
use: 'babel-loader',
include: [
resolvePath('src'),
resolvePath('node_modules/framework7'),
resolvePath('node_modules/framework7-vue'),
},
devtool: env === 'production' ? 'source-map' : 'eval',
devServer: {
hot: false, //Changed
open: true,
compress: true,
contentBase: '/www/',
disableHostCheck: true,
historyApiFallback: true,
watchOptions: {
poll: 1000,
},
},
optimization: {
minimizer: [
new TerserPlugin({
sourceMap: true,
}),
],
},
module: {
rules: [
{
test: /\.(mjs|js|jsx)$/,
use: 'babel-loader',
include: [
resolvePath('src'),
resolvePath('node_modules/framework7'),
resolvePath('node_modules/framework7-vue'),
resolvePath('node_modules/template7'),
resolvePath('node_modules/dom7'),
resolvePath('node_modules/ssr-window'),
],
},
resolvePath('node_modules/template7'),
resolvePath('node_modules/dom7'),
resolvePath('node_modules/ssr-window'),
],
},
{
test: /\.vue$/,
use: 'vue-loader',
},
{
test: /\.css$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
}),
'css-loader',
'postcss-loader',
],
},
{
test: /\.styl(us)?$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
}),
'css-loader',
'postcss-loader',
'stylus-loader',
],
},
{
test: /\.less$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
}),
'css-loader',
'postcss-loader',
'less-loader',
],
},
{
test: /\.(sa|sc)ss$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
}),
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: `images/[name]${hashName}.[ext]`,
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac|m4a)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: `media/[name]${hashName}.[ext]`,
{
test: /\.vue$/,
use: 'vue-loader',
},
{
test: /\.css$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}),
'css-loader',
'postcss-loader',
],
},
{
test: /\.styl(us)?$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}),
'css-loader',
'postcss-loader',
'stylus-loader',
],
},
{
test: /\.less$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}),
'css-loader',
'postcss-loader',
'less-loader',
],
},
{
test: /\.(sa|sc)ss$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}),
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]',
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: `fonts/[name]${hashName}.[ext]`,
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac|m4a)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name].[ext]',
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[ext]',
},
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env),
'process.env.TARGET': JSON.stringify(target),
}),
new VueLoaderPlugin(),
...(env === 'production' ? [
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
map: { inline: false },
},
}),
new webpack.optimize.ModuleConcatenationPlugin(),
] : [
// Development only plugins
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
]),
new HtmlWebpackPlugin({
filename: './index.html',
template: './src/index.html',
inject: true,
minify: env === 'production' ? {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
} : false,
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
}),
new CopyWebpackPlugin({
patterns: [
{
noErrorOnMissing: true,
from: resolvePath('src/static'),
to: resolvePath(isCordova ? 'cordova/www/static' : 'www/static'),
},
{
noErrorOnMissing: true,
from: resolvePath('src/manifest.json'),
to: resolvePath('www/manifest.json'),
},
],
}),
...(!isCordova ? [
new WorkboxPlugin.InjectManifest({
swSrc: resolvePath('src/service-worker.js'),
})
] : []),
],
},
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env),
'process.env.TARGET': JSON.stringify(target),
}),
new VueLoaderPlugin(),
...(env === 'production' ? [
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
map: {inline: false},
},
}),
new webpack.optimize.ModuleConcatenationPlugin(),
] : [
// Development only plugins
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
]),
new HtmlWebpackPlugin({
filename: './index.html',
template: './src/index.html',
inject: true,
minify: env === 'production' ? {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
} : false,
}),
new MiniCssExtractPlugin({
filename: `css/[name]${hashName}.css`,
}),
new CopyWebpackPlugin({
patterns: [
{
noErrorOnMissing: true,
from: resolvePath('src/static'),
to: resolvePath(isCordova ? 'cordova/www/static' : 'www/static'),
},
{
noErrorOnMissing: true,
from: resolvePath('src/.htaccess'),
to: resolvePath('www'),
},
{
noErrorOnMissing: true,
from: resolvePath('src/manifest.json'),
to: resolvePath('www/manifest.json'),
},
{
noErrorOnMissing: true,
from: resolvePath('src/robots.txt'),
to: resolvePath('www/robots.txt'),
},
{
noErrorOnMissing: true,
from: resolvePath('src/sitemap.xml'),
to: resolvePath('www/sitemap.xml'),
},
{
noErrorOnMissing: true,
from: resolvePath('src/assetlinks.json'),
to: resolvePath('www/.well-known'),
},
],
}),
...(!isCordova ? [
new WorkboxPlugin.InjectManifest({
swSrc: resolvePath('src/service-worker.js'),
}),
] : []),
],
};
......@@ -5,7 +5,7 @@
<author email="info@ablota.com" href="https://ablota.com">Ablota (StarApps GmbH)</author>
<content src="index.html"/>
<access origin="https://store.ablota.com"/>
<access origin="https://api.store.ablota.com"/>
<allow-intent href="http://*/*"/>
<allow-intent href="https://*/*"/>
<allow-intent href="mailto:*"/>
......
......@@ -11,9 +11,9 @@
"dev": true
},
"@ablota/store-cordova-plugin": {
"version": "1.0.0",
"resolved": "https://gitlab.starapps-network.com/api/v4/projects/34/packages/npm/@ablota/store-cordova-plugin/-/@ablota/store-cordova-plugin-1.0.0.tgz",
"integrity": "sha1-A9Y1N/0ABxuSYo1g3cTu0P1oTsw=",
"version": "1.0.1",
"resolved": "https://gitlab.starapps-network.com/api/v4/projects/34/packages/npm/@ablota/store-cordova-plugin/-/@ablota/store-cordova-plugin-1.0.1.tgz",
"integrity": "sha1-U9REcXaMdp5+/Q56mHtMpV3ollk=",
"dev": true
},
"@develar/schema-utils": {
......
......@@ -27,7 +27,7 @@
]
},
"devDependencies": {
"@ablota/store-cordova-plugin": "^1.0.0",
"@ablota/store-cordova-plugin": "^1.0.1",
"cordova-android": "^9.0.0",
"cordova-clipboard": "^1.3.0",
"cordova-electron": "^2.0.0",
......
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE "application/atom+xml" "application/javascript" "application/json" "application/ld+json" "application/manifest+json" "application/rdf+xml" "application/rss+xml" "application/schema+json" "application/vnd.geo+json" "application/vnd.ms-fontobject" "application/x-font-ttf" "application/x-javascript" "application/x-web-app-manifest+json" "application/xhtml+xml" "application/xml" "font/eot" "font/opentype" "image/bmp" "image/svg+xml" "image/vnd.microsoft.icon" "image/x-icon" "text/cache-manifest" "text/css" "text/html" "text/javascript" "text/plain" "text/vcard" "text/vnd.rim.location.xloc" "text/vtt" "text/x-component" "text/x-cross-domain-policy" "text/xml"
</IfModule>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|ico|gif|jpeg|jpg|png|svg|eot|ttf|woff|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
</IfModule>
<IfModule mod_rewrite.c>
RewriteCond %{HTTP_HOST} =ablota.store [NC]
RewriteRule ^(.*)$ https://store.ablota.com/$1 [R=301,NE,L]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,NE,L]
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE,L]
ErrorDocument 404 https://%{HTTP_HOST}
</IfModule>
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.ablota.store",
"sha256_cert_fingerprints": [
"5E:A5:AE:2F:48:1E:00:E1:B0:A3:88:CA:4E:CC:0B:84:B3:89:1A:6C:0B:32:F5:9C:59:AA:B2:A0:71:A2:51:46"
]
}
}
]
......@@ -24,7 +24,7 @@
return {
url: 'https://store.ablota.com/',
server: {
url: 'http://localhost:8000/'
url: 'https://api.store.ablota.com/'
},
};
},
......
......@@ -14,7 +14,7 @@
<div class="timeline-item-inner">
<div class="timeline-item-title">{{ $t('words.download') }}</div>
<div class="timeline-item-text">{{ $t('popups.downloadApp.steps.download.description') }}</div>
<f7-button href="https://ablota.com/repo/Ablota_Store.apk" :text="$t('words.download')" fill raised></f7-button>
<f7-button href="https://ablota.com/repo/Ablota_Store.apk" :text="$t('words.download')" fill raised external></f7-button>
</div>
</div>
</div>
......@@ -45,7 +45,7 @@
<div class="timeline-item-inner">
<div class="timeline-item-title">{{ $t('words.done') }}</div>
<div class="timeline-item-text">{{ $t('popups.downloadApp.steps.done.description') }}</div>
<f7-button href="https://store.ablota.com" :text="$t('words.launch')" fill raised></f7-button>
<f7-button href="https://store.ablota.com" :text="$t('words.launch')" fill raised external></f7-button>
</div>
</div>
</div>
......
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8">
<% if (process.env.NODE_ENV === 'production') { %>
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' 'unsafe-eval' data: gap: content: https://store.ablota.com">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' 'unsafe-eval' data: gap: content: https://api.store.ablota.com">
<% } %>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover" name="viewport">
<meta content="#007aff" name="theme-color">
<meta content="telephone=no" name="format-detection">
<meta content="no" name="msapplication-tap-highlight">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta property="og:image:width" content="128">
<meta property="og:image:height" content="128">
<meta property="og:description" content="The universal, decentralized and open source app store.">
<meta property="og:title" content="Ablota Store">
<meta property="og:url" content="https://store.ablota.com">
<meta property="og:image" content="https://store.ablota.com/static/icons/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="robots" content="noarchive, notranslate, noimageindex">
<meta name="theme-color" content="#007aff">
<meta name="format-detection" content="telephone=no">
<meta name="format-detection" content="date=no">
<meta name="format-detection" content="address=no">
<meta name="msapplication-TileColor" content="#007aff">
<meta name="msapplication-tap-highlight" content="no">