Rich Contenty – co trzeba wiedzieć
Rich Content to specyficzny format contentu i w zależności od wydawcy jego przygotowanie będzie wyglądać nieco inaczej. W tym artykule dowiesz się jak skonfigurować projekt i poznasz dobre praktyki dzięki którym zminimalizujesz ryzyko błędów.
Kilka podstawowych zasad
- paczka pojedynczego rc powinna ważyć jak najmniej dlatego warto pamiętać aby w miarę możliwości skompresować wszystkie grafiki ( polecam https://www.iloveimg.com/compress-image )
- najczęściej dozwolone formaty plików graficznych to jpg oraz png
- pamiętaj o dodawaniu wersji paczek oraz plików
- unikaj dołączania zewnętrznych bibliotek ( często są one zabronione )
- jeśli rc wymaga napisania skryptu zrób to w czystym js’ie
- zapoznaj się ze szczegółową specyfikacją techniczną jeśli istnieje
- za nim wyślesz finalną paczkę poproś kolegę / koleżankę z zespołu o rzucenie okiem i przetestowanie
Stylowanie
W zależności od sposoby w jaki RC zostanie osadzony przyjmujemy dwa podejścia do stylowania.
- Jeśli RC zostanie osadzony bezpośrednio na stronie
Ustawiamy style dla wszystkich elementów statycznie w px uwzględniając breakpointsy wydawcy
- Jeśli RC zostanie osadzony jako iframe
Ustawiamy style dla wszystkich elementów bazując na vm oraz vh. W tym przypadku trzeba pamiętać że naszą wyjściowym punktem do przeliczeń będzie szerokość iframe dlatego podgląd podczas pracy nad projektem powinien być również jako iframe. W innym przypadku wielkości zostaną przeliczone względem szerokości przeglądarki i po wrzuceniu do iframe wielkości mogą się różnić.
Istnieje możliwość obejścia tego problemu poprzez zastosowanie container query units ale nie jest to jeszcze w pełni wspierane
https://ishadeed.com/article/container-query-units/
Konfiguracja projektu
W zależności od wydawcy konfiguracja projektu może się od siebie różnić. Niektórzy osadzają RC bezpośrednio w stukurze swoich serwisów a inni jako iframe. Należy zawsze zwrócić uwagę na wymagania odnośnie sposobu budowania struktury katalogowej oraz ustawieniu odpowiednich ścieżek.
Paczki generowane są przy pomocy gulpa a jego podstawowa konfiguracja wygląda następująco
const { watch, src, dest, series, parallel } = require('gulp');
const browserSync = require('browser-sync').create();
const autoprefixer = require('gulp-autoprefixer');
const sass = require('gulp-sass')(require('sass'));
const del = require('del');
const tinypng = require('gulp-tinypng-compress');
const cssmin = require('gulp-cssmin');
const rename = require('gulp-rename');
const replace = require('gulp-replace');
var dataArry = [
{
id: 0,
ean_number: '3474637109387',
product_name: 'product_name',
assets_path: 'userdata/public/assets/cards/loreal-professionnel/scalp/',
}
];
const config = {
name: 'semilac/extendy',
app: {
scss: './dev/assets/scss/main.scss',
images: './dev/assets/img/',
html: './dev/base.html',
css: './dev/assets/css',
js: './dev/assets/js',
fonts: './dev/assets/fonts/**/*.*',
},
dist: {
base: './dist/**',
}
}
const cleanTemp = (done) => del('./dev/assets/_temp/**/*.*')
const tinypngTask = (done) => {
src('./dev/assets/_temp/**/*.{png,jpg,jpeg,ico}')
.pipe(tinypng({
key: 'SFfxZhtQHN2lS2GCgK4k3Svr54bBjm5s',
log: true
}))
.pipe(dest('./dev/assets/img/'))
done();
}
const moveImages = (done) => {
src('./dev/assets/img/**/*.{png,jpg,jpeg,ico}')
.pipe(dest('./dev/assets/_temp'))
done();
}
const cleanImages = (done) => {
return del('./asssets/dev/img');
}
const cssTask = (done) => {
src(config.app.scss)
.pipe(sass({
outputStyle: 'expanded'
}))
.pipe(autoprefixer({
cascade: false
}))
.pipe(dest(
config.app.css
))
done();
}
const cssDist = (done) => {
dataArry.forEach(function(obj) {
src(config.app.css + '/**.css')
.pipe(rename({
basename: "loreal-professionnel-scalp",
}))
.pipe(dest('./dist/css'))
done();
});
}
const cleanDist = () => {
return del(config.dist.base);
}
const imagesTask = (done) => {
dataArry.forEach(function(obj) {
src(config.app.images + obj.product_name + '/**/*.*')
.pipe(dest('./dist/' + obj.assets_path + obj.product_name))
done();
});
}
const watchFiles = () => {
watch(config.app.html, series(indexReplace, reload));
watch(config.app.scss, series(cssTask, reload));
}
const reload = (done) => {
browserSync.reload();
done();
}
const browser = () => {
browserSync.init({
server: {
baseDir: './dev/'
}
});
}
const indexReplace = (done) => {
src(['./dev/base.html'])
.pipe(replace('{{text_replace}}', dataArry[0].text_replace))
.pipe(rename("index.html"))
.pipe(dest('./dev/'))
done();
}
const indexDist = (done) => {
dataArry.forEach(function(obj) {
src(['./dev/base.html'])
.pipe(replace('{{text_replace}}', obj.text_replace))
.pipe(rename(obj.ean_number + ".html"))
.pipe(dest('./dist/'))
done();
});
}
const fontsDist = (done) => {
dataArry.forEach(function(obj) {
src(config.app.fonts)
.pipe(dest('./dist/' + obj.assets_path + '/fonts'))
done();
});
}
exports.dev = parallel(
cssTask,
watchFiles,
// indexReplace,
browser,
);
exports.build = series(
cleanDist,
parallel(
cssDist,
imagesTask,
indexDist,
// jsDist,
// fontsDist,
)
);
exports.compress = series(
cleanTemp,
moveImages,
cleanImages,
tinypngTask,
);
Struktura katalogowa
nazwa_klienta
- nazwa_wydawcy
- gulpfile.js
- package.json
- dev
- base.html
- index.html
- assets
- css
- js
- img
- fonts
- dist
Odpalenia projektu w trybie deweloperskim
gulp dev
W tym momencie na podstawie pliku base.html zostanie wygenerowany index.html który będzie nadpisywany za każdym razem kiedy wprowadzimy zmiany w base.html lub plikach css i js. W przeglądarce otworzy się nowe okno z podglądem projektu, zmiany będą odświeżane automatycznie.
Podmian tekstu
Jeśli teksty w projekcie dla każdego produktu mogę się różnić należy uwzględnić je w strukturze oraz konfiguracji. W funkcji indexReplace oraz indexDist należy dodać następującą instrukcje
// indexReplace
.pipe(replace('{{text_replace}}', dataArry[0].text_replace))
dataArry[0] – możemy podmienić na dowolny identyfikator z tablicy produktowej jeśli chcemy mieć podgląd konkretnego produktu.
//indexDist
.pipe(replace('{{text_replace}}', obj.text_replace))
Po każdej tego typu operacji musimy zrestartować proces
Budowanie paczki
Przed zbudowaniem paczki należy określić ścieżki docelowe dla wszystkich zasobów tak aby zgadzały się z specyfikacją oraz strukturą html
Dla każdego zasoby mamy możliwość określenia docelowej ścieżki ( funkcje fontsDist, indexDist, cssDist, imagesTask )
Możemy zdefiniować ją statycznie lub dynamicznie na bazie danych z tablicy
src(config.app.images + obj.product_name + '/**/*.*')
.pipe(dest('./dist/project_name/css'))
done();
src(config.app.images + obj.product_name + '/**/*.*')
.pipe(dest('./dist/' + obj.assets_path + obj.product_name))
done();
const imagesTask = (done) => {
dataArry.forEach(function(obj) {
src(config.app.images + obj.product_name + '/**/*.*')
.pipe(dest('./dist/' + obj.assets_path + obj.product_name))
done();
});
}
const fontsDist = (done) => {
dataArry.forEach(function(obj) {
src(config.app.fonts)
.pipe(dest('./dist/' + obj.assets_path + '/fonts'))
done();
});
}
const cssDist = (done) => {
dataArry.forEach(function(obj) {
src(config.app.css + '/**.css')
.pipe(rename({
basename: "css_file_name",
}))
.pipe(dest('./dist/css'))
done();
});
}
Funkcja indexDist podczas generowania pliku docelowego odpowiedzialna jest za podmianę ścieżek do plików oraz wygenerowania właściwych tekstów.
const indexDist = (done) => {
dataArry.forEach(function(obj) {
src(['./dev/base.html'])
.pipe(replace('{{text_replace}}', obj.text_replace))
.pipe(replace('assets/img/base', obj.assets_path + obj.product_name))
.pipe(replace('assets/css/main.css', './css/css_file_name.css'))
.pipe(rename(obj.ean_number + ".html"))
.pipe(dest('./dist/'))
done();
});
}
Na koniec w celu zbudowania paczki należy wykonać polecenie
gulp build