クラフトCMSの複数のページのサイトでCreate Reactionアプリを使用する方法
すでに使用方法をカバーする記事がたくさんありますCraft CMS 反応するが、それらは主にGraphSQLの使用に集中します.このポストでは、我々は偉大な使用方法を参照してくださいCreate React App テンプレートは、クラフトCMSと一緒に、両方の世界のベストを得るために:コミュニティ最適化された反応アプリ、バトルテストフロントエンドツール、ページごとに異なるバンドルを持つ複数のエントリポイントをテストした.
我々はすべてのプロセスを通して一緒に行くだろう、私たちの前にかなりの旅があるので、始めましょう.
I recommend to have at least basic knowledges about Craft CMS, PHP, CRA, and a good comprehension of Webpack
CRAをテンプレートでインストールする
Since v3.3 react-scripts support templates , 我々は素晴らしいを使用しますreact boilerplate template 特にv5-with-cra branch これは、typescriptサポートを追加しますが、必須ではありませんany templates , またはあなたのニーズに応じてすべてのテンプレートは、とにかく継続することができます:For what follows our project will be named cracraft, and CRA refer to Create react app
$ npx create-react-app --template cra-template-rb cracraft
修正されたテンプレートのエラーこのエラーに遭遇した場合、
A template was not provided. This is likely because you're using an outdated version of create-react-app.
Please note that global installs of create-react-app are no longer supported.
まず、すべてのグローバルインストールされたCRAのバージョンを削除します.npm uninstall -g create-react-app
yarn global remove create-react-app
error This module isn't specified in a package.json file.
彼を盲目に信じないでください.$ readlink which `create-react-app`
そして、あなたがパスを得るならば、それはあなたのシステムに残るCRAパッケージのもう一つのバージョンです;だから、それを削除してみてください.インストールされたら、ディレクトリにCDを実行する
npm start
すべてがスムーズに実行していることを確認します.CMSのインストール
Installing Craft CMS is quite simple, thanks to composer , しかし、小さな問題があります.非空のディレクトリにインストールすることはできません.composer create-project craftcms/craft cracraft-temp
cracraft-temp
ディレクトリこのセットアップの目的は、TwigテンプレートでCRAを統合するだけでなく、1ページのアプリケーションのために仕事をするでしょう、しかし、いくつかのページが本当に複雑なウィジェットまたは複雑なアプリケーションを含むことができた複数のページでウェブサイトのために、そして、他のものはちょうどJavaScriptのいくつかの線またはJavaScriptなしを必要とします.もっと柔軟性が必要だ.
しかし、CRAとして設計されているとしても、それは本当に柔軟性がありません、それは意味があります、それはスパであるために作られたので、1つのHTMLページがあります、そして、あなたは全部の束または何も注入しません.この時点で、我々は現在、片面では、CMSによって供給された複数のページのサイトを持っている一方、CRAによって供給されたスパで、我々は2つの融合する必要があります.
CRACOを使用したカスタマイズCRA
Let’s customize CRA to play well with Craft CMS, the goal is to tweak the Webpack configuration without ejecting, and thus keep the advantages of being able to update either CRA or the template.
There are a couple of options for customization:
$ npm install @craco/craco --save
次に、ルートディレクトリ、すべての修正を含むファイルを作成しますcraco.config.js
.そして、最終的にスタートを更新して、反応スクリプトの代わりにcracoを使用するスクリプトコマンドを構築してください.
インパッケージ.JSON
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
...
},
If you want to know more about the full details of the craco installation, it’s here
それは、いくつかのコードを書く時間です.
ここでは、
.env
ファイルWDS_SOCKET_HOST=localhost
WDS_SOCKET_PORT=3000
PUBLIC_PATH="http://localhost:3000/"
MANIFEST_PATH=/asset-manifest.json
FAST_REFRESH=true
FAST_REFRESH enable react-refresh, it’s not mandatory to enable it, but it’s allow to improve components updates
変更とビルドパス
Assuming that the src
directory contains all the javascript and styles sources, and that we want to output the result of the build step in web/dist
:
cracraft
├── src
│ ├── styles
│ │ ├── **/*.css
│ ├── app
│ │ ├── **/*.tsx
│ ├── js
│ │ ├── **/*.js
│ └── ...
├── web
│ ├── dist
│ └── ...
├── templates
├── craco.config.js
├── .env
└── ...
We have to tell Webpack where our files are and where we want the output, both for dev and build mode:
In craco.config.js
const {
whenDev,
whenProd,
} = require('@craco/craco');
module.exports = function ({ env }) {
return {
webpack: {
configure: (webpackConfig, { env, paths }) => {
whenDev(() => {
webpackConfig.output.publicPath = process.env.PUBLIC_PATH;
});
whenProd(() => {
const buildPath = `${paths.appPath}/web${process.env.PUBLIC_PATH}`;
paths.appBuild = buildPath;
webpackConfig.output.path = buildPath;
webpackConfig.output.publicPath = process.env.PUBLIC_PATH;
return webpackConfig;
});
}
},
plugins: [],
style: {}
}
}
Using a local domain like .local
To avoid CORS errors between your local domain and the dev server, add a header to the webpack dev server, using craco’s ability to change the configuration of the dev server.
In craco.config.js
...
plugins: [
{
plugin: {
overrideDevServerConfig: ({
devServerConfig,
cracoConfig,
pluginOptions,
context: { env, paths, proxy, allowedHost },
}) => {
devServerConfig.headers = {
'Access-Control-Allow-Origin': '*',
};
return devServerConfig;
},
}
},
],
...
複数のエントリポイントのサポートを追加する
CRA doesn’t support multiple entry points out of the box, so we have to reconfigure Webpack to add some. Let’s say we have 3 different pages:
- home where we want to use Typescript
- editor a page containing the react SPA
- about a page that need only a simple javascript snippet
NB: Dont forget to create these pages and their associated Twig templates
In craco.config.js add our 3 entry points
...
module.exports = function ({ env }) {
return {
webpack: {
configure: (webpackConfig, { env, paths }) => {
const entries = {
index: [...webpackConfig.entry],
home: [`${paths.appSrc}/js/home.ts`],
about: [`${paths.appSrc}/js/about/index.js`],
};
...
}
}
}
}
It won’t work yet, because the ManifestPlugin already used in CRA will cause a problem, it is configured 単一のエントリポイントをサポートします.そして、Webpackプラグインの設定を上書きするためには、それを置き換える必要があります.Note: We keep index as name for the entry point of the react SPA
プラグインをインストールします
$ npm i ManifestPlugin -D
プラグインの新しいインスタンスを作成し、プラグイン配列の既存のものを置き換えます.クラコで.設定.js
...
module.exports = function ({ env }) {
return {
webpack: {
configure: (webpackConfig, { env, paths }) => {
...
// Substitute ManifestPlugin:
const pluginPosition = webpackConfig.plugins.findIndex(
({ constructor }) => constructor.name === 'ManifestPlugin',
);
const multipleEntriesManifestPlugin = new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
// Keep the existing entry point
const indexEntrypointFiles = entrypoints.index.filter(
fileName => !fileName.endsWith('.map'),
);
let { index, ...pagesAllEntryPointFiles } = entrypoints;
// Create our pages entry points
const pagesEntryPointFiles = Object.keys(
pagesAllEntryPointFiles,
).reduce((filtered, entryKey) => {
filtered[entryKey] = pagesAllEntryPointFiles[entryKey].filter(
fileName => !fileName.endsWith('.map'),
);
return filtered;
}, {});
return {
files: manifestFiles,
entrypoints: indexEntrypointFiles,
pages: pagesEntryPointFiles,
};
},
});
webpackConfig.plugins.splice(
pluginPosition,
1,
multipleEntriesManifestPlugin,
);
...
}
}
}
}
そして、ホップ!それは完了です、我々はちょうどプラグインを置き換えました.我々はほとんど完了している、私たちの新しいエントリポイントをサポートするために残っている1つのステップがあります、私たちは
webpackHotDevClient
それぞれがサポートするHMR クラコで.設定.js
...
whenDev(() => {
webpackConfig.output.publicPath = process.env.PUBLIC_PATH;
webpackConfig.optimization.runtimeChunk = 'single';
const webpackHotDevClientPath = require.resolve(
'react-dev-utils/webpackHotDevClient',
);
Object.keys(entries).forEach(entryKey => {
if (!entries[entryKey].includes(webpackHotDevClientPath)) {
entries[entryKey].unshift(webpackHotDevClientPath);
}
});
});
...
簡単なヒント:カスタマイズCRAをカスタマイズし、トリッキーなバグに遭遇する場合は、まだ任意のNODEJSアプリのようなプロセスをデバッグすることができますを覚えて
--inspect
NPMスクリプトコマンドへのフラグcraco --inspect build
風船と微調整ポストを加える
Once everything is in place and the dev server plus the build step are running without any errors, we can customize further to integrate all our needs, for the demonstration we’ll add a favicon plugin, customize Postcss and use Tailwind CSSフレームワーク.まず最初に、TarwindとPostCSSはとても簡単です.必要なパッケージを追加することから始めます.
$ npm i -D postcss-import postcss-preset-env tailwindcss
プロジェクトのルートディレクトリでtailwind.config.js
ファイル.クラコで.設定.PostScriptの設定を追加する
...
style: {
postcss: {
plugins: [
require('postcss-import')({
plugins: [require('stylelint')],
path: ['./node_modules'],
}),
require('tailwindcss')('./tailwind.config.js'),
require('postcss-preset-env')({
autoprefixer: {},
features: {
'nesting-rules': true,
},
})
],
},
},
...
そして、それを完璧にするために、我々はTrewindで使用されるいくつかの正統的な規則でチルアウトするStyleLintを指示する必要があります.これらの規則を
.stylelintrc
設定ファイル:"rules": {
"at-rule-no-unknown": [ true, {
"ignoreAtRules": [
"screen",
"extends",
"responsive",
"tailwind"
]
}],
"block-no-empty": null
}
別のプラグインを追加
Next, add the Favicons Webpack Plugin, here it’s even simplier because we just have to push it in the Webpack config plugin array, provided by craco, like this:
whenProd(() => {
...
webpackConfig.plugins.push(
new FaviconsWebpackPlugin({
logo: './src/img/favicon-src.png',
prefix: 'img/favicons/',
cache: true,
inject: 'force',
favicons: {
appName: 'Cracraft',
appDescription: 'Create react app and Craft play well together',
developerName: 'Dev name',
developerURL: '[email protected]',
path: 'web/dist/',
},
}),
);
});
Note that when you add a plugin which is already used in the CRA config you have to replace it, using the same trick as the one used previously for the ManifestPlugin.
必要に応じて各テンプレートに関連するJSファイルとCSSファイルを注入する
Ooook now that CRA is customized, there is one last step to link it to Craft CMS: we need to retrieve the content of the different endpoints, and, since the manifest file is a plain json file, it’s easy to read it and get the parts we need.
How are we going to do that?
- Quick answer: this can be done with a Twig function
- Long answer: there is a better way to do it, but we’ll talk about it in another post, as this one is starting to be quite long (congrats if you're still reading from the beginning).
So, lets write a simple Twig function that will load our manifest file and create the HTML tags.
First install a PHP implementation of JsonPath$ composer require galbar/jsonpath
Twig拡張子を宣言するファイルで、すべての依存関係をインポートします.use craft\helpers\Html;
use craft\helpers\Template;
use craft\helpers\Json as JsonHelper;
use JsonPath\JsonObject;
そして、マニフェストファイルの内容を取得し、探しているチャンクのパスを返す関数を追加しますそれをgetentrypointchunksと呼びましょう、そして、それは$jsonPath
Param、コードを通してください.public function getEntryPointChunks(string $path)
{
$publicPath = getenv('PUBLIC_PATH');
$manifestPath = getenv('MANIFEST_PATH');
$manifestContent = file_get_contents($publicPath.$manifestPath);
$manifest = JsonHelper::decodeIfJson($manifestContent);
$jsonObject = new JsonObject($manifestContent);
$moduleList = $jsonObject->get($jsonPath);
if (!$moduleList) {
return null;
}
// Ensure flat array, ex: if [*] is forgotten in the json path to an array
if (is_array($moduleList)) {
$flattened = [];
array_walk_recursive($moduleList, function ($item) use (&$flattened) {
$flattened[] = $item;
});
$moduleList = $flattened;
}
$moduleTags = [];
foreach ($moduleList as $k => $m) {
if (strpos($m, '.hot-update.js') === false) {
$moduleName = preg_replace('/^\//', '', $m);
if (preg_match('/\.css(\?.*)?$/i', $moduleName)) {
$moduleTags[] = Html::cssFile("$publicPath/$moduleName");
} elseif (preg_match('/\.js(\?.*)?$/i', $moduleName)) {
$moduleTags[] = Html::jsFile("$publicPath/$moduleName");
} elseif (preg_match('/\.(svg|png|jpe?g|webp|avif|gif)(\?.*)?$/i', $moduleName)) {
$moduleTags[] = Html::img("$publicPath/$moduleName");
} else {
$moduleTags[] = "$publicPath/$moduleName";
}
}
}
return Template::raw(implode("\r\n", $moduleTags));
}
そして最後に、任意のtwigテンプレートから関数を呼び出します.{# Inject the spa react app #}
{{getEntryPointChunks('$.entrypoints')}}
と別のページ{# Inject vanilla javascript #}
{{getEntryPointChunks('$.pages.about')}}
NB: don’t forget to start the development server before accessing your Craft site
$ npm start
そして、それはこれです、これは終わりです、我々はマルチエントリーポイントセットアップとカスタマイズ可能なWebpack構成でCRAとCraft CMSの間で(ほぼ)完全な融合を持ちます.
次回は、このセットアップをクラフトCMSですべてを統合するより良い方法で完了する予定です.なぜなら、Twig機能は仕事をしていますが、改善の余地があるからです.
読書のおかげで、何か新しいことを学び、それはあなたを助ける願っています.
Reference
この問題について(クラフトCMSの複数のページのサイトでCreate Reactionアプリを使用する方法), 我々は、より多くの情報をここで見つけました https://dev.to/fraqe/cra-craft-how-to-use-create-react-app-in-a-craft-cms-multiple-pages-site-19fcテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol