Enable plugin development in JS project.

Added loader for ts.
Created default tsconfig file

Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
soupette 2022-04-14 10:59:42 +02:00
parent 91cbfef66e
commit 84bd88a230
13 changed files with 195 additions and 65 deletions

View File

@ -17,7 +17,8 @@ type Auth = {
const config: Config = {
auth: {
logo: 'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
logo:
'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
},
head: {
favicon:
@ -26,7 +27,8 @@ const config: Config = {
},
locales: ['fr'],
menu: {
logo: 'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
logo:
'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
},
theme,
translations: {

View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string", "DOM"],
"noImplicitAny": false,
"module": "es2020",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"noEmit": false,
"incremental": true
},
"include": ["../plugins/**/admin/src/**/*", "./"],
"exclude": ["node_modules", "**/*.test.js", "*.js"]
}

View File

@ -0,0 +1,39 @@
import theme from './extensions/theme';
const config = {
auth: {
logo:
'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
},
head: {
favicon:
'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
title: 'Strapi tesrrt',
},
locales: ['fr', 'de'],
menu: {
logo:
'https://images.unsplash.com/photo-1593642634367-d91a135587b5?ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80',
},
theme,
translations: {
fr: {
'Auth.form.email.label': 'test',
Users: 'Utilisateurs',
City: 'CITY FRENCH',
// Customize the label of the CM table..
Id: 'ID french',
},
},
tutorials: false,
notifications: { release: false },
};
const bootstrap = app => {
console.log(app);
};
export default {
config,
bootstrap,
};

View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string", "DOM"],
"noImplicitAny": false,
"module": "es2020",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"noEmit": false,
"incremental": true
},
"include": [
"./",
"../../../**/admin/src/**/*",
"../../../../plugins/documentation/admin/src/**/*"
],
"exclude": ["node_modules", "**/*.test.js", "*.js"]
}

View File

@ -4,7 +4,9 @@ const path = require('path');
const fs = require('fs-extra');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const { isTypeScriptProject } = require('@strapi/typescript-utils');
const chalk = require('chalk');
const {
createCacheDir,
getCustomWebpackConfig,
@ -12,24 +14,20 @@ const {
watchAdminFiles,
} = require('./utils');
async function build({
appDir,
buildDestDir,
env,
forceBuild,
optimize,
options,
plugins,
useTypeScript,
}) {
const buildAdmin = await shouldBuildAdmin({ appDir, plugins, useTypeScript });
async function build({ appDir, buildDestDir, env, forceBuild, optimize, options, plugins }) {
const buildAdmin = await shouldBuildAdmin({ appDir, plugins });
const useTypeScript = await isTypeScriptProject(
path.join(appDir, 'src', 'admin'),
'tsconfig.json'
);
if (!buildAdmin && !forceBuild) {
return;
}
// Create the cache dir containing the front-end files.
await createCacheDir({ appDir, plugins, useTypeScript });
await createCacheDir({ appDir, plugins });
const cacheDir = path.resolve(appDir, '.cache');
const entry = path.resolve(cacheDir, 'admin', 'src');
@ -43,6 +41,12 @@ async function build({
const pluginsPath = Object.keys(plugins).map(pluginName => plugins[pluginName].appPathToPlugin);
// Either use the tsconfig file from the generated app or the one inside the .cache folder
// so we can develop plugins in TS while being in a JS app
const tsConfigFilePath = useTypeScript
? path.join(appDir, 'src', 'admin', 'tsconfig.json')
: path.resolve(entry, 'tsconfig.json');
const config = getCustomWebpackConfig(appDir, {
appDir,
cacheDir,
@ -53,7 +57,7 @@ async function build({
options,
pluginsPath,
roots,
useTypeScript,
tsConfigFilePath,
});
const compiler = webpack(config);
@ -94,19 +98,14 @@ async function clean({ appDir, buildDestDir }) {
fs.removeSync(cacheDir);
}
async function watchAdmin({
appDir,
browser,
buildDestDir,
host,
options,
plugins,
port,
useTypeScript,
}) {
async function watchAdmin({ appDir, browser, buildDestDir, host, options, plugins, port }) {
const useTypeScript = await isTypeScriptProject(
path.join(appDir, 'src', 'admin'),
'tsconfig.json'
);
// Create the cache dir containing the front-end files.
const cacheDir = path.join(appDir, '.cache');
await createCacheDir({ appDir, plugins, useTypeScript });
await createCacheDir({ appDir, plugins });
const entry = path.join(cacheDir, 'admin', 'src');
const dest = path.join(buildDestDir, 'build');
@ -120,6 +119,12 @@ async function watchAdmin({
const pluginsPath = Object.keys(plugins).map(pluginName => plugins[pluginName].appPathToPlugin);
// Either use the tsconfig file from the generated app or the one inside the .cache folder
// so we can develop plugins in TS while being in a JS app
const tsConfigFilePath = useTypeScript
? path.join(appDir, 'src', 'admin', 'tsconfig.json')
: path.resolve(entry, 'tsconfig.json');
const args = {
appDir,
cacheDir,
@ -147,7 +152,7 @@ async function watchAdmin({
disableDotRule: true,
},
},
useTypeScript,
tsConfigFilePath,
};
const webpackConfig = getCustomWebpackConfig(appDir, args);

View File

@ -53,6 +53,7 @@
"@strapi/babel-plugin-switch-ee-ce": "4.1.7",
"@strapi/design-system": "0.0.1-alpha.79",
"@strapi/helper-plugin": "4.1.7",
"@strapi/typescript-utils": "4.1.7",
"@strapi/icons": "0.0.1-alpha.79",
"@strapi/utils": "4.1.7",
"axios": "0.24.0",

View File

@ -22,6 +22,8 @@ const smp = new SpeedMeasurePlugin();
const buildAdmin = async () => {
const entry = path.join(__dirname, '..', 'admin', 'src');
const dest = path.join(__dirname, '..', 'build');
const tsConfigFilePath = path.join(__dirname, '..', 'admin', 'src', 'tsconfig.json');
const corePlugins = getCorePluginsPath();
const plugins = getPluginToInstallPath(PLUGINS_TO_INSTALL);
const allPlugins = { ...corePlugins, ...plugins };
@ -40,6 +42,7 @@ const buildAdmin = async () => {
backend: 'http://localhost:1337',
adminPath: '/admin/',
},
tsConfigFilePath,
};
const config =

View File

@ -3,6 +3,7 @@
const path = require('path');
const _ = require('lodash');
const fs = require('fs-extra');
const { isTypeScriptProject } = require('@strapi/typescript-utils');
const getCustomAppConfigFile = require('./get-custom-app-config-file');
const getPkgPath = name => path.dirname(require.resolve(`${name}/package.json`));
@ -67,9 +68,14 @@ async function copyAdmin(dest) {
await fs.copy(path.resolve(adminPath, 'package.json'), path.resolve(dest, 'package.json'));
}
async function createCacheDir({ appDir, plugins, useTypeScript }) {
async function createCacheDir({ appDir, plugins }) {
const cacheDir = path.resolve(appDir, '.cache');
const useTypeScript = await isTypeScriptProject(
path.join(appDir, 'src', 'admin'),
'tsconfig.json'
);
const pluginsWithFront = Object.keys(plugins)
.filter(pluginName => {
const pluginInfo = plugins[pluginName];
@ -115,6 +121,44 @@ async function createCacheDir({ appDir, plugins, useTypeScript }) {
// create plugins.js with plugins requires
await createPluginsJs(pluginsWithFront, cacheDir);
// create the tsconfig.json file so we can develop plugins in ts while being in a JS project
if (!useTypeScript) {
await createTSConfigFile(cacheDir);
}
}
async function createTSConfigFile(dest) {
const tsConfig = {
compilerOptions: {
lib: ['es2019', 'es2020.promise', 'es2020.bigint', 'es2020.string', 'DOM'],
noImplicitAny: false,
module: 'es2020',
target: 'es5',
jsx: 'react',
allowJs: true,
strict: true,
moduleResolution: 'node',
skipLibCheck: true,
esModuleInterop: true,
allowSyntheticDefaultImports: true,
resolveJsonModule: true,
noEmit: false,
incremental: true,
},
include: ['../../../src/admin/src/*', '../../../src/**/**/admin/src/*'],
exclude: ['node_modules', '**/*.test.js', '*.js'],
};
const filePath = path.join(dest, 'admin', 'src', 'tsconfig.json');
try {
await fs.ensureFile(filePath);
await fs.writeJSON(filePath, tsConfig, { spaces: 2 });
} catch (err) {
console.log(err);
}
}
module.exports = createCacheDir;

View File

@ -2,15 +2,17 @@
const { join } = require('path');
const fse = require('fs-extra');
const { isTypeScriptProject } = require('@strapi/typescript-utils');
/**
* Retrieve the custom admin entry file name
* @param {String} dir - Directory of the admin panel
* @param {Boolean} useTypeScript - Does the custom admin entry file use TS
* @returns String
*/
const getCustomAppConfigFile = async (dir, useTypeScript) => {
const getCustomAppConfigFile = async dir => {
const adminSrcPath = join(dir, 'src', 'admin');
const useTypeScript = await isTypeScriptProject(adminSrcPath, 'tsconfig.json');
const files = await fse.readdir(adminSrcPath);
const appRegex = new RegExp(`app.${useTypeScript ? 't' : 'j'}sx?$`);

View File

@ -30,10 +30,10 @@ const hasNonDefaultPlugins = plugins => {
return diff.length > 0;
};
const hasCustomAdminCode = async (dir, useTypeScript) => {
const hasCustomAdminCode = async dir => {
const customAdminPath = path.join(dir, 'src', 'admin');
const customAdminAppConfigFile = await getCustomAppConfigFile(dir, useTypeScript);
const customAdminAppConfigFile = await getCustomAppConfigFile(dir);
const customAdminWebpackFile = path.join(customAdminPath, 'webpack.config.js');
const hasCustomConfigFile = !!customAdminAppConfigFile;
@ -42,8 +42,8 @@ const hasCustomAdminCode = async (dir, useTypeScript) => {
return hasCustomConfigFile || hasCustomWebpackFile;
};
const shouldBuildAdmin = async ({ appDir, plugins, useTypeScript }) => {
const appHasCustomAdminCode = await hasCustomAdminCode(appDir, useTypeScript);
const shouldBuildAdmin = async ({ appDir, plugins }) => {
const appHasCustomAdminCode = await hasCustomAdminCode(appDir);
const appHasNonDefaultPlugins = hasNonDefaultPlugins(plugins);
return appHasCustomAdminCode || appHasNonDefaultPlugins;

View File

@ -3,13 +3,16 @@
const path = require('path');
const fs = require('fs-extra');
const chokidar = require('chokidar');
const { isTypeScriptProject } = require('@strapi/typescript-utils');
/**
* Listen to files change and copy the changed files in the .cache/admin folder
* when using the dev mode
* @param {string} dir
*/
async function watchAdminFiles(dir, useTypeScript) {
async function watchAdminFiles(dir) {
const useTypeScript = await isTypeScriptProject(path.join(dir, 'src', 'admin'), 'tsconfig.json');
const cacheDir = path.join(dir, '.cache');
const targetExtensionFile = useTypeScript ? 'app.tsx' : 'app.js';
const appExtensionFile = path.join(dir, 'src', 'admin', targetExtensionFile);

View File

@ -28,6 +28,7 @@ module.exports = () => {
dest,
env,
options,
tsConfigFilePath: path.resolve(__dirname, 'admin', 'src', 'tsconfig.json'),
};
const config = webpackConfig(args);

View File

@ -13,7 +13,6 @@ const alias = require('./webpack.alias');
const getClientEnvironment = require('./env');
module.exports = ({
appDir,
cacheDir,
dest,
entry,
@ -29,7 +28,7 @@ module.exports = ({
eeRoot: './ee/admin',
ceRoot: './admin/src',
},
useTypeScript,
tsConfigFilePath,
}) => {
const isProduction = env === 'production';
@ -50,34 +49,14 @@ module.exports = ({
]
: [];
if (useTypeScript) {
const tsChecker = new ForkTsCheckerPlugin({
typescript: {
// FIXME
configFile: path.join(appDir, 'tsconfig-admin.json'),
},
});
const tsChecker = new ForkTsCheckerPlugin({
typescript: {
// FIXME
configFile: tsConfigFilePath,
},
});
webpackPlugins.push(tsChecker);
}
const rules = [];
// webpack is quite slow to compile so it is best not to use the ts loader when
// it is not needed in javascript apps.
// Users can still add it by using the custom webpack config.
if (useTypeScript) {
rules.push({
test: /\.tsx?$/,
loader: require.resolve('esbuild-loader'),
include: [cacheDir, ...pluginsPath],
exclude: /node_modules/,
options: {
loader: 'tsx',
target: 'es2015',
},
});
}
webpackPlugins.push(tsChecker);
// Directly inject a polyfill in the webpack entry point before the entry point
// FIXME: I have noticed a bug regarding the helper-plugin and esbuild-loader
@ -112,6 +91,16 @@ module.exports = ({
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: require.resolve('esbuild-loader'),
include: [cacheDir, ...pluginsPath],
exclude: /node_modules/,
options: {
loader: 'tsx',
target: 'es2015',
},
},
{
test: /\.m?js$/,
include: cacheDir,
@ -222,7 +211,6 @@ module.exports = ({
},
},
},
...rules,
],
},
resolve: {