Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

WIP: webpackify the framework #228

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"global-require": "off",
"import/no-dynamic-require": "off",
"no-console": "off",
"no-use-before-define": ["error", { "functions": false }]
"no-use-before-define": ["error", { "functions": false }],
"semi": ["ERROR", "never"],
"no-unreachable": "ERROR",
"comma-dangle": "off"
}
}
134 changes: 67 additions & 67 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
const fs = require('fs');
const path = require('path');
const git = require('git-rev-sync');
const { generatePdfAt, generatePdfFromHtml } = require('./pdf/generate-pdf-with-chrome');
const fs = require('fs')
const path = require('path')
const git = require('git-rev-sync')
const { generatePdfAt, generatePdfFromHtml } = require('./pdf/generate-pdf-with-chrome')

module.exports = function gruntConfig(grunt) {
const port = grunt.option('port') || 8000;
const configFormation = grunt.file.readJSON('package.json');
const prefixPdfName = `Zenika-Formation${configFormation.name ? `-${configFormation.name}` : ''}`;
const slidesPdfName = `${prefixPdfName}-Slides`;
const cahierExercicesPdfName = `${prefixPdfName}-CahierExercices`;
const date = new Date().toISOString().slice(0, 10);
const version = `${date}#${git.short()}`;
const frameworkPath = __dirname;
const port = grunt.option('port') || 8000
const configFormation = grunt.file.readJSON('package.json')
const prefixPdfName = `Zenika-Formation${configFormation.name ? `-${configFormation.name}` : ''}`
const slidesPdfName = `${prefixPdfName}-Slides`
const cahierExercicesPdfName = `${prefixPdfName}-CahierExercices`
const date = new Date().toISOString().slice(0, 10)
const version = `${date}#${git.short()}`
const frameworkPath = __dirname

const slidesFolder = grunt.option('slides-folder') || 'Slides';
const labsFolder = grunt.option('labs-folder') || 'CahierExercices';
const slidesFolder = grunt.option('slides-folder') || 'Slides'
const labsFolder = grunt.option('labs-folder') || 'CahierExercices'

function resolveNpmModulesPath(npmModulePath) {
try {
fs.accessSync(pathIfNpm2(npmModulePath));
return pathIfNpm2(npmModulePath);
fs.accessSync(pathIfNpm2(npmModulePath))
return pathIfNpm2(npmModulePath)
} catch (e) {
// let's try npm3
}
return pathIfNpm3(npmModulePath);
return pathIfNpm3(npmModulePath)
}

function pathIfNpm2(npmModulePath) {
return path.resolve(frameworkPath, 'node_modules', npmModulePath);
return path.resolve(frameworkPath, 'node_modules', npmModulePath)
}

function pathIfNpm3(npmModulePath) {
return path.resolve(frameworkPath, '..', npmModulePath);
return path.resolve(frameworkPath, '..', npmModulePath)
}

grunt.initConfig({
Expand Down Expand Up @@ -98,15 +98,15 @@ module.exports = function gruntConfig(grunt) {
src: 'index.html',
dest: 'slides.html',
rename(dest) {
return `${frameworkPath}/${dest}`;
return `${frameworkPath}/${dest}`
},
}, {
expand: true,
cwd: frameworkPath,
src: 'summary.html',
dest: 'index.html',
rename(dest) {
return `${frameworkPath}/${dest}`;
return `${frameworkPath}/${dest}`
},
},
],
Expand Down Expand Up @@ -185,7 +185,7 @@ module.exports = function gruntConfig(grunt) {
'index.html',
],
rename(dest) {
return `${dest}/slides.html`;
return `${dest}/slides.html`
},
},
{
Expand All @@ -196,7 +196,7 @@ module.exports = function gruntConfig(grunt) {
'summary.html',
],
rename(dest) {
return `${dest}/index.html`;
return `${dest}/index.html`
},
},
{
Expand Down Expand Up @@ -291,66 +291,66 @@ module.exports = function gruntConfig(grunt) {
'grunt-contrib-copy/tasks',
'grunt-filerev/tasks',
'grunt-filerev-replace/tasks',
].map(resolveNpmModulesPath).forEach(grunt.loadTasks);
].map(resolveNpmModulesPath).forEach(grunt.loadTasks)

grunt.registerTask('package', ['sed', 'justPdf', 'clean:dist', 'copy:dist', 'filerev-all']);
grunt.registerTask('filerev-all', ['filerev', 'filerev_replace']);
grunt.registerTask('package', ['sed', 'justPdf', 'clean:dist', 'copy:dist', 'filerev-all'])
grunt.registerTask('filerev-all', ['filerev', 'filerev_replace'])

grunt.registerTask('displaySlides', ['sed', 'connect:server', 'watch']);
grunt.registerTask('displaySlides', ['sed', 'connect:server', 'watch'])

grunt.registerTask('generateCahierExercice', async function generateCahierExercice() {
const done = this.async();
const done = this.async()

const Remarkable = require('remarkable');
const base64img = require('base64-img');
const hljs = require('highlight.js');
const Remarkable = require('remarkable')
const base64img = require('base64-img')
const hljs = require('highlight.js')

let parts;
let parts
try {
parts = require(path.resolve(frameworkPath, '..', '..', labsFolder, 'parts.json'));
parts = require(path.resolve(frameworkPath, '..', '..', labsFolder, 'parts.json'))
} catch (e) {
parts = ['Cahier.md'];
parts = ['Cahier.md']
}
const cssPath = path.resolve(frameworkPath, 'styleCahierExercice.css');
const highlightPath = path.resolve(frameworkPath, 'reveal', 'theme-zenika', 'code.css');
const files = parts.map(file => path.resolve(labsFolder, file));
const cssPath = path.resolve(frameworkPath, 'styleCahierExercice.css')
const highlightPath = path.resolve(frameworkPath, 'reveal', 'theme-zenika', 'code.css')
const files = parts.map(file => path.resolve(labsFolder, file))

console.log('Using CSS file', cssPath);
console.log('Using highlightPath file', highlightPath);
console.log('Using md sources files', files);
console.log('Using CSS file', cssPath)
console.log('Using highlightPath file', highlightPath)
console.log('Using md sources files', files)

// from https://github.com/jonschlinkert/remarkable#syntax-highlighting
function highlight(str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
return hljs.highlight(lang, str).value
} catch (err) {
// ignore
}
}
try {
return hljs.highlightAuto(str).value;
return hljs.highlightAuto(str).value
} catch (err) {
// ignore
}
return ''; // use external default escaping
return '' // use external default escaping
}

try {
const markdownContent = files.map(file => fs.readFileSync(file)).join('\n\n');
const cssContent = fs.readFileSync(cssPath);
const highlightJsCssContent = fs.readFileSync(highlightPath);
const remarkable = new Remarkable({ html: true, highlight });
const markdownContent = files.map(file => fs.readFileSync(file)).join('\n\n')
const cssContent = fs.readFileSync(cssPath)
const highlightJsCssContent = fs.readFileSync(highlightPath)
const remarkable = new Remarkable({ html: true, highlight })
const htmlContent = remarkable.render(markdownContent)
.replace(/<img (.*)src=["|']([^"']*)["|'](.*)>/g, (match, p1, p2, p3) => `<img ${p1}src="${base64img.base64Sync(path.resolve(labsFolder, p2))}"${p3}>`)
.replace(/\{Titre-Formation}/g, () => configFormation.name);
.replace(/\{Titre-Formation}/g, () => configFormation.name)
const htmlContentWithStyles = `
${htmlContent}
<style>
${cssContent}
${highlightJsCssContent}
</style>
`;
`
const pdfContent = await generatePdfFromHtml(htmlContentWithStyles, {
format: 'A4',
margin: {
Expand All @@ -359,37 +359,37 @@ module.exports = function gruntConfig(grunt) {
bottom: '8mm',
left: '8mm',
},
});
grunt.file.write(`PDF/${cahierExercicesPdfName}.pdf`, pdfContent, { encoding: 'base64' });
done();
})
grunt.file.write(`PDF/${cahierExercicesPdfName}.pdf`, pdfContent, { encoding: 'base64' })
done()
} catch (err) {
grunt.log.error(err);
done(false);
grunt.log.error(err)
done(false)
}
});
})

grunt.registerTask('doGenerateSlidesPDF', async function doGenerateSlidesPDF() {
const done = this.async();
const done = this.async()
try {
const pdf = await generatePdfAt(`http://localhost:${port}?print-pdf`, {
landscape: true,
printBackground: true,
format: 'A4',
});
grunt.file.write(`PDF/${slidesPdfName}.pdf`, pdf, { encoding: 'base64' });
done();
})
grunt.file.write(`PDF/${slidesPdfName}.pdf`, pdf, { encoding: 'base64' })
done()
} catch (err) {
grunt.log.error(err);
done(false);
grunt.log.error(err)
done(false)
}
});
})


grunt.registerTask('generateSlidesPDF', ['connect:print', 'doGenerateSlidesPDF']);
grunt.registerTask('generateSlidesPDF', ['connect:print', 'doGenerateSlidesPDF'])

grunt.registerTask('justPdf', ['generateSlidesPDF', 'generateCahierExercice']);
grunt.registerTask('justPdf', ['generateSlidesPDF', 'generateCahierExercice'])

grunt.registerTask('pdf', ['sed', 'justPdf']);
grunt.registerTask('pdf', ['sed', 'justPdf'])

grunt.registerTask('default', ['displaySlides']);
};
grunt.registerTask('default', ['displaySlides'])
}
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@

# Notes temporaires de la branche webpack

* faire un checkout du framework de formation zenika, tirer la branche `webpack`
* lier la dépendance au framework de formation :

```sh
npm link ../zenika-formation-framework
```

Todo / issues :

* [x] supprimer les dépendances à webpack des projets de formation pour qu'elles ne soient que dans le framework de formation
* [x] affecter le nom de la formation dans le head.title de la page web
* [x] affecter le numéro de version dans le css
* [ ] les images incluses "à la html" (pour pouvoir inclure du stylage CSS inline) dans les .md ne sont pas gérées
* [ ] celles incluses dans les titres de niveau 1 posent pb à cause du stylage `height: 90%;`

Questions :

* le numéro de version concatène une date et un n° commit : est-ce celui de la formation ou du framework de formation ?

# Zenika Formation Framework

Utilisé par toutes nos formations, comme sur le [Modèle](https://github.com/Zenika/Formation--Modele)
Expand Down Expand Up @@ -35,8 +57,8 @@ Le code de Reveal, ainsi que le thème utilisé, se trouve dans le framework de

### Architecture

Pour une formation F donnée,
le framework se trouve dans le répertoire `./node_modules/zenika-formation-framework/`, le contenu des slides dans `./Slides/`.
Pour une formation F donnée,
le framework se trouve dans le répertoire `./node_modules/zenika-formation-framework/`, le contenu des slides dans `./Slides/`.
Le serveur utilise 2 baseDir qui sont `./node_modules/zenika-formation-framework/`, puis `./Slides/`.
Ainsi, il est possible d'utiliser des ressources dans le contenu des slides (dans les fichiers `./Slides/*.md`) avec un chemin relatif simple.

Expand Down Expand Up @@ -107,7 +129,7 @@ De base, tous les builds sont repertoriés sur Slack dans le channel `#ic-format
Pour cela, aller dans CircleCI > Settings du projet > Chat Notifications et indiquer dans le panel Slack `https://hooks.slack.com/services/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`

NB: Url directe pour le paramétrage `https://circleci.com/gh/Zenika/formation-pwa/edit#hooks`

## Troobleshooting

Dans le [wiki](https://github.com/Zenika/zenika-formation-framework/wiki/Troubleshooting)
Expand Down
50 changes: 25 additions & 25 deletions deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,39 @@

// or else the Gruntfile from the depending project will run the code!
if (require.main === module) {
const execFileSync = require('child_process').execFileSync;
const fs = require('fs');
const execFileSync = require('child_process').execFileSync
const fs = require('fs')

const tempKeyFile = 'file.key';
const gcloudSdkVersion = '135.0.0';
const serviceAccount = process.env.GAE_SERVICE_ACCOUNT;
const gcloudProject = 'zen-formations';
const gcloudService = process.env.npm_package_name;
const currentBranch = process.env.CURRENT_BRANCH;
const tempKeyFile = 'file.key'
const gcloudSdkVersion = '135.0.0'
const serviceAccount = process.env.GAE_SERVICE_ACCOUNT
const gcloudProject = 'zen-formations'
const gcloudService = process.env.npm_package_name
const currentBranch = process.env.CURRENT_BRANCH

if (!serviceAccount || !currentBranch) {
console.log('Environment variables GAE_SERVICE_ACCOUNT or CURRENT_BRANCH not set.');
console.log('Please check both are defined when running this script.');
process.exit(1);
console.log('Environment variables GAE_SERVICE_ACCOUNT or CURRENT_BRANCH not set.')
console.log('Please check both are defined when running this script.')
process.exit(1)
}

fs.writeFileSync(tempKeyFile, process.env.GAE_KEY_FILE_CONTENT);
fs.writeFileSync(tempKeyFile, process.env.GAE_KEY_FILE_CONTENT)
try {
if (!process.argv.includes('--no-gcloud-update')) {
console.log(`Updating Google Cloud SDK to version ${gcloudSdkVersion}`);
execFileSync('gcloud', ['config', 'set', '--installation', 'component_manager/fixed_sdk_version', gcloudSdkVersion]);
execFileSync('gcloud', ['version']);
execFileSync('sudo', ['/opt/google-cloud-sdk/bin/gcloud', '--quiet', 'components', 'update']);
execFileSync('gcloud', ['version']);
console.log(`Updating Google Cloud SDK to version ${gcloudSdkVersion}`)
execFileSync('gcloud', ['config', 'set', '--installation', 'component_manager/fixed_sdk_version', gcloudSdkVersion])
execFileSync('gcloud', ['version'])
execFileSync('sudo', ['/opt/google-cloud-sdk/bin/gcloud', '--quiet', 'components', 'update'])
execFileSync('gcloud', ['version'])
}
console.log('Configuring Google Cloud SDK');
execFileSync('gcloud', ['config', 'set', 'app/use_appengine_api', 'false']);
execFileSync('gcloud', ['config', 'set', 'app/promote_by_default', 'false']);
console.log('Authenticate with', serviceAccount);
execFileSync('gcloud', ['auth', 'activate-service-account', serviceAccount, '--key-file', tempKeyFile]);
console.log(`Deploying to ${gcloudService}-dot-${gcloudProject}`);
execFileSync('gcloud', ['--project', gcloudProject, 'app', 'deploy', '--version', currentBranch, '--quiet', 'dist/app.yaml']);
console.log('Configuring Google Cloud SDK')
execFileSync('gcloud', ['config', 'set', 'app/use_appengine_api', 'false'])
execFileSync('gcloud', ['config', 'set', 'app/promote_by_default', 'false'])
console.log('Authenticate with', serviceAccount)
execFileSync('gcloud', ['auth', 'activate-service-account', serviceAccount, '--key-file', tempKeyFile])
console.log(`Deploying to ${gcloudService}-dot-${gcloudProject}`)
execFileSync('gcloud', ['--project', gcloudProject, 'app', 'deploy', '--version', currentBranch, '--quiet', 'dist/app.yaml'])
} finally {
fs.unlinkSync(tempKeyFile);
fs.unlinkSync(tempKeyFile)
}
}
Loading