enhancement: use script instead of bootstrap for example seed

This commit is contained in:
Alexandre Bodin 2024-09-16 15:43:52 +02:00
parent ec7fb54b20
commit 30e5d19d03
22 changed files with 363 additions and 48 deletions

View File

@ -0,0 +1,241 @@
{
"global": {
"siteName": "Strapi Blog",
"defaultSeo": {
"metaTitle": "Page",
"metaDescription": "A blog made with Strapi",
"shareImage": null
},
"siteDescription": "A Blog made with Strapi",
"favicon": null
},
"about": {
"title": "About the strapi blog",
"blocks": [
{
"__component": "shared.quote",
"title": "Thelonius Monk",
"body": "You've got to dig it to dig it, you dig?"
},
{
"__component": "shared.rich-text",
"body": "## Dedit imago conspicuus cum capillis totidem inhibere\n\nLorem markdownum **rerum**, est limine: columbas: ab infelix hostem arbore nudis\ncrudelis. Videtur reliquit ambo ferrum dote sub amne fatis **illuc**, in magis,\nnec."
},
{
"__component": "shared.media",
"file": "coffee-art.jpg"
}
]
},
"categories": [
{
"name": "news",
"slug": "news"
},
{
"name": "tech",
"slug": "tech"
},
{
"name": "food",
"slug": "food"
},
{
"name": "nature",
"slug": "nature"
},
{
"name": "story",
"slug": "story"
}
],
"authors": [
{
"name": "David Doe",
"email": "daviddoe@strapi.io",
"avatar": "daviddoe@strapi.io.jpg"
},
{
"name": "Sarah Baker",
"email": "sarahbaker@strapi.io",
"avatar": "sarahbaker@strapi.io.jpg"
}
],
"articles": [
{
"title": "The internet's Own boy",
"slug": "the-internet-s-own-boy",
"category": {
"id": 5
},
"author": {
"id": 1
},
"description": "Follow the story of Aaron Swartz, the boy who could change the world",
"cover": null,
"blocks": [
{
"__component": "shared.rich-text",
"body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
},
{
"__component": "shared.quote",
"title": "Thelonius Monk",
"body": "You've got to dig it to dig it, you dig?"
},
{
"__component": "shared.media",
"file": "coffee-art.jpg"
},
{
"__component": "shared.rich-text",
"body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
},
{
"__component": "shared.slider",
"files": ["coffee-art.jpg", "coffee-beans.jpg"]
}
]
},
{
"title": "This shrimp is awesome",
"slug": "this-shrimp-is-awesome",
"category": {
"id": 4
},
"author": {
"id": 1
},
"description": "Mantis shrimps, or stomatopods, are marine crustaceans of the order Stomatopoda.",
"cover": null,
"blocks": [
{
"__component": "shared.rich-text",
"body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
},
{
"__component": "shared.quote",
"title": "Thelonius Monk",
"body": "You've got to dig it to dig it, you dig?"
},
{
"__component": "shared.media",
"file": "coffee-art.jpg"
},
{
"__component": "shared.rich-text",
"body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
},
{
"__component": "shared.slider",
"files": ["coffee-art.jpg", "coffee-beans.jpg"]
}
]
},
{
"title": "A bug is becoming a meme on the internet",
"slug": "a-bug-is-becoming-a-meme-on-the-internet",
"category": {
"id": 2
},
"author": {
"id": 2
},
"description": "How a bug on MySQL is becoming a meme on the internet",
"cover": null,
"blocks": [
{
"__component": "shared.rich-text",
"body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
},
{
"__component": "shared.quote",
"title": "Thelonius Monk",
"body": "You've got to dig it to dig it, you dig?"
},
{
"__component": "shared.media",
"file": "coffee-art.jpg"
},
{
"__component": "shared.rich-text",
"body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
},
{
"__component": "shared.slider",
"files": ["coffee-art.jpg", "coffee-beans.jpg"]
}
]
},
{
"title": "Beautiful picture",
"slug": "beautiful-picture",
"category": {
"id": 4
},
"author": {
"id": 2
},
"description": "Description of a beautiful picture",
"cover": null,
"blocks": [
{
"__component": "shared.rich-text",
"body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
},
{
"__component": "shared.quote",
"title": "Thelonius Monk",
"body": "You've got to dig it to dig it, you dig?"
},
{
"__component": "shared.media",
"file": "coffee-art.jpg"
},
{
"__component": "shared.rich-text",
"body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
},
{
"__component": "shared.slider",
"files": ["coffee-art.jpg", "coffee-beans.jpg"]
}
]
},
{
"title": "What's inside a Black Hole",
"slug": "what-s-inside-a-black-hole",
"category": {
"id": 1
},
"author": {
"id": 2
},
"description": "Maybe the answer is in this article, or not...",
"cover": null,
"blocks": [
{
"__component": "shared.rich-text",
"body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
},
{
"__component": "shared.quote",
"title": "Thelonius Monk",
"body": "You've got to dig it to dig it, you dig?"
},
{
"__component": "shared.media",
"file": "coffee-art.jpg"
},
{
"__component": "shared.rich-text",
"body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
},
{
"__component": "shared.slider",
"files": ["coffee-art.jpg", "coffee-beans.jpg"]
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -40,6 +40,8 @@ async function createApp(scope: Scope) {
runApp,
} = scope;
const shouldRunSeed = useExample && installDependencies;
await trackUsage({ event: 'willCreateProject', scope });
logger.title('Strapi', `Creating a new application at ${chalk.green(rootPath)}`);
@ -150,10 +152,26 @@ async function createApp(scope: Scope) {
logger.success('Initialized a git repository.');
}
logger.title('Strapi', `Your application was created!`);
if (shouldRunSeed) {
if (await fse.exists(join(rootPath, 'scripts/seed.js'))) {
logger.title('Seed', 'Seeding your database with sample data');
try {
await execa(packageManager, ['run', 'seed:example'], {
stdio: 'inherit',
cwd: rootPath,
});
logger.success('Sample data added to your database');
} catch (error) {
logger.error('Failed to seed your database. Skipping');
}
}
}
const cmd = chalk.cyan(`${packageManager} run`);
logger.title('Strapi', `Your application was created!`);
logger.log([
'Available commands in your project:',
'',
@ -169,19 +187,28 @@ async function createApp(scope: Scope) {
'Deploy Strapi project.',
`${cmd} deploy`,
'',
'Display all available commands.',
`${cmd} strapi\n`,
]);
if (useExample) {
logger.log(['Seed your database with sample data.', `${cmd} seed:example`, '']);
}
logger.log(['Display all available commands.', `${cmd} strapi\n`]);
if (installDependencies) {
logger.log(['To get started run', '', `${chalk.cyan('cd')} ${rootPath}`, `${cmd} develop`]);
logger.log([
'To get started run',
'',
`${chalk.cyan('cd')} ${rootPath}`,
!shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`,
]);
} else {
logger.log([
'To get started run',
'',
`${chalk.cyan('cd')} ${rootPath}`,
`${chalk.cyan(packageManager)} install`,
`${cmd} develop`,
!shouldRunSeed && useExample ? `${cmd} seed:example && ${cmd} develop` : `${cmd} develop`,
]);
}

View File

@ -38,7 +38,7 @@ async function example() {
type: 'confirm',
name: 'useExample',
message: 'Start with an example structure & data?',
default: true,
default: false,
},
]);

View File

@ -4,7 +4,8 @@
"start": "strapi start",
"build": "strapi build",
"strapi": "strapi",
"deploy": "strapi deploy"
"deploy": "strapi deploy",
"seed:example": "node ./scripts/seed.js"
},
"dependencies": {
"fs-extra": "^10.0.0",

View File

@ -5,6 +5,25 @@ const path = require('path');
const mime = require('mime-types');
const { categories, authors, articles, global, about } = require('../data/data.json');
async function seedExampleApp() {
const shouldImportSeedData = await isFirstRun();
if (shouldImportSeedData) {
try {
console.log('Setting up the template...');
await importSeedData();
console.log('Ready to go');
} catch (error) {
console.log('Could not import seed data');
console.error(error);
}
} else {
console.log(
'Seed data has already been imported. We cannot reimport unless you clear your database first.'
);
}
}
async function isFirstRun() {
const pluginStore = strapi.store({
environment: strapi.config.environment,
@ -235,17 +254,21 @@ async function importSeedData() {
await importAbout();
}
module.exports = async () => {
const shouldImportSeedData = await isFirstRun();
async function main() {
const { createStrapi, compileStrapi } = require('@strapi/strapi');
if (shouldImportSeedData) {
try {
console.log('Setting up the template...');
await importSeedData();
console.log('Ready to go');
} catch (error) {
console.log('Could not import seed data');
console.error(error);
}
}
};
const appContext = await compileStrapi();
const app = await createStrapi(appContext).load();
app.log.level = 'error';
await seedExampleApp();
await app.destroy();
process.exit(0);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -1,5 +1,4 @@
'use strict';
const bootstrap = require('./bootstrap');
module.exports = {
/**
@ -17,5 +16,5 @@ module.exports = {
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
bootstrap,
bootstrap(/*{ strapi }*/) {},
};

View File

@ -4,7 +4,8 @@
"start": "strapi start",
"build": "strapi build",
"strapi": "strapi",
"deploy": "strapi deploy"
"deploy": "strapi deploy",
"seed:example": "node ./scripts/seed.js"
},
"dependencies": {
"fs-extra": "^10.0.0",

View File

@ -1,9 +1,11 @@
import fs from 'fs-extra';
import path from 'path';
import mime from 'mime-types';
import { categories, authors, articles, global, about } from '../data/data.json';
'use strict';
export async function bootstrap() {
const fs = require('fs-extra');
const path = require('path');
const mime = require('mime-types');
const { categories, authors, articles, global, about } = require('../data/data.json');
async function seedExampleApp() {
const shouldImportSeedData = await isFirstRun();
if (shouldImportSeedData) {
@ -15,10 +17,14 @@ export async function bootstrap() {
console.log('Could not import seed data');
console.error(error);
}
} else {
console.log(
'Seed data has already been imported. We cannot reimport unless you clear your database first.'
);
}
}
async function isFirstRun(): Promise<boolean> {
async function isFirstRun() {
const pluginStore = strapi.store({
environment: strapi.config.environment,
type: 'type',
@ -29,7 +35,7 @@ async function isFirstRun(): Promise<boolean> {
return !initHasRun;
}
async function setPublicPermissions(newPermissions: { [key: string]: string[] }) {
async function setPublicPermissions(newPermissions) {
// Find the ID of the public role
const publicRole = await strapi.query('plugin::users-permissions.role').findOne({
where: {
@ -38,8 +44,8 @@ async function setPublicPermissions(newPermissions: { [key: string]: string[] })
});
// Create the new permissions and link them to the public role
const allPermissionsToCreate: any[] = [];
Object.keys(newPermissions).forEach((controller) => {
const allPermissionsToCreate = [];
Object.keys(newPermissions).map((controller) => {
const actions = newPermissions[controller];
const permissionsToCreate = actions.map((action) => {
return strapi.query('plugin::users-permissions.permission').create({
@ -54,13 +60,13 @@ async function setPublicPermissions(newPermissions: { [key: string]: string[] })
await Promise.all(allPermissionsToCreate);
}
function getFileSizeInBytes(filePath: string): number {
function getFileSizeInBytes(filePath) {
const stats = fs.statSync(filePath);
const fileSizeInBytes = stats['size'];
return fileSizeInBytes;
}
function getFileData(fileName: string) {
function getFileData(fileName) {
const filePath = path.join('data', 'uploads', fileName);
// Parse the file metadata
const size = getFileSizeInBytes(filePath);
@ -75,7 +81,7 @@ function getFileData(fileName: string) {
};
}
async function uploadFile(file: any, name: string) {
async function uploadFile(file, name) {
return strapi
.plugin('upload')
.service('upload')
@ -92,10 +98,9 @@ async function uploadFile(file: any, name: string) {
}
// Create an entry and attach files if there are any
async function createEntry({ model, entry }: { model: string; entry: any }) {
async function createEntry({ model, entry }) {
try {
// Actually create the entry in Strapi
//@ts-ignore
await strapi.documents(`api::${model}.${model}`).create({
data: entry,
});
@ -104,9 +109,9 @@ async function createEntry({ model, entry }: { model: string; entry: any }) {
}
}
async function checkFileExistsBeforeUpload(files: string[]): Promise<any> {
const existingFiles: any[] = [];
const uploadedFiles: any[] = [];
async function checkFileExistsBeforeUpload(files) {
const existingFiles = [];
const uploadedFiles = [];
const filesCopy = [...files];
for (const fileName of filesCopy) {
@ -123,7 +128,7 @@ async function checkFileExistsBeforeUpload(files: string[]): Promise<any> {
} else {
// File doesn't exist, upload it
const fileData = getFileData(fileName);
const fileNameNoExtension = fileName.split('.').shift() || '';
const fileNameNoExtension = fileName.split('.').shift();
const [file] = await uploadFile(fileData, fileNameNoExtension);
uploadedFiles.push(file);
}
@ -133,8 +138,8 @@ async function checkFileExistsBeforeUpload(files: string[]): Promise<any> {
return allFiles.length === 1 ? allFiles[0] : allFiles;
}
async function updateBlocks(blocks: any[]): Promise<any[]> {
const updatedBlocks: any[] = [];
async function updateBlocks(blocks) {
const updatedBlocks = [];
for (const block of blocks) {
if (block.__component === 'shared.media') {
const uploadedFiles = await checkFileExistsBeforeUpload([block.file]);
@ -173,7 +178,7 @@ async function importArticles() {
cover,
blocks: updatedBlocks,
// Make sure it's not a draft
publishedAt: new Date(),
publishedAt: Date.now(),
},
});
}
@ -188,7 +193,7 @@ async function importGlobal() {
...global,
favicon,
// Make sure it's not a draft
publishedAt: new Date(),
publishedAt: Date.now(),
defaultSeo: {
...global.defaultSeo,
shareImage,
@ -206,7 +211,7 @@ async function importAbout() {
...about,
blocks: updatedBlocks,
// Make sure it's not a draft
publishedAt: new Date(),
publishedAt: Date.now(),
},
});
}
@ -248,3 +253,22 @@ async function importSeedData() {
await importGlobal();
await importAbout();
}
async function main() {
const { createStrapi, compileStrapi } = require('@strapi/strapi');
const appContext = await compileStrapi();
const app = await createStrapi(appContext).load();
app.log.level = 'error';
await seedExampleApp();
await app.destroy();
process.exit(0);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -1,5 +1,4 @@
// import type { Core } from '@strapi/strapi';
import { bootstrap } from './bootstrap';
export default {
/**
@ -17,5 +16,5 @@ export default {
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
bootstrap,
bootstrap(/* { strapi }: { strapi: Core.Strapi } */) {},
};