diff --git a/packages/babel-plugin-nunjucks/README.md b/packages/babel-plugin-nunjucks/README.md
new file mode 100644
index 0000000..89dc630
--- /dev/null
+++ b/packages/babel-plugin-nunjucks/README.md
@@ -0,0 +1,70 @@
+# babel-plugin-nunjucks
+
+Плагин для [babel-loader](https://github.com/babel/babel-loader), позволяющий использовать шаблонизатор [Nunjucks](https://mozilla.github.io/nunjucks/) внутри JS-файлов.
+
+## Установка
+
+```bash
+yarn add -D @advdominion/babel-plugin-nunjucks
+```
+
+## Использование
+
+Используются [Tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) с тегом `njk`:
+
+```js
+njk`
+ {% from "./item.njk" import item as item %}
+
+
+ {% for n in range(0, 10) %}
+ {{item()}}
+ {% endfor %}
+
+`;
+```
+
+Пример конфигурации Webpack:
+
+```js
+[
+ {
+ test: /\.js$/,
+ exclude: [/mocks\.js$/],
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ cacheDirectory: true,
+ },
+ },
+ ],
+ },
+ {
+ test: /mocks\.js$/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ compact: false,
+ plugins: [
+ [
+ '@advdominion/babel-plugin-nunjucks',
+ {
+ templatesFolder: 'src/templates/',
+ },
+ ],
+ ],
+ },
+ },
+ ],
+ },
+];
+```
+
+## Опции
+
+- `templatesFolder` - строка, обязательный параметр. Путь до папки с файлами шаблонов
+- `globals` - массив, необязательный параметр. Глобальные переменные для Nunjucks (например, `[{name: "message", value: "Hello, world!"}]`)
+
+**Важно:** Параметр `cacheDirectory` в опциях babel-loader должен быть отключён.
diff --git a/packages/babel-plugin-nunjucks/index.js b/packages/babel-plugin-nunjucks/index.js
new file mode 100644
index 0000000..72dd2ff
--- /dev/null
+++ b/packages/babel-plugin-nunjucks/index.js
@@ -0,0 +1,129 @@
+/* eslint-disable unicorn/no-useless-spread */
+
+import js from '@eslint/js';
+import eslintConfigPrettier from 'eslint-config-prettier';
+import simpleImportSort from 'eslint-plugin-simple-import-sort';
+import eslintPluginUnicorn from 'eslint-plugin-unicorn';
+import pluginVue from 'eslint-plugin-vue';
+import globals from 'globals';
+
+const config = [
+ {
+ languageOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ globals: {
+ ...globals.browser,
+ ...globals.nodeBuiltin,
+ },
+ },
+ },
+ js.configs.recommended,
+ {
+ rules: {
+ ...{
+ 'array-callback-return': 'error',
+ 'no-await-in-loop': 'warn',
+ 'no-duplicate-imports': 'warn',
+ 'no-promise-executor-return': 'error',
+ 'no-self-compare': 'error',
+ 'no-template-curly-in-string': 'warn',
+ 'no-unassigned-vars': 'warn',
+ 'no-unmodified-loop-condition': 'error',
+ 'no-unreachable-loop': 'error',
+ 'no-use-before-define': 'error',
+ 'no-useless-assignment': 'warn',
+ },
+ ...{
+ 'dot-notation': 'warn',
+ 'eqeqeq': 'error',
+ 'no-implicit-coercion': 'warn',
+ 'no-negated-condition': 'warn',
+ 'no-useless-concat': 'warn',
+ 'object-shorthand': 'warn',
+ 'func-style': 'error',
+ 'no-console': ['warn', { allow: ['warn', 'error'] }],
+ 'no-param-reassign': 'error',
+ 'no-var': 'error',
+ 'one-var': ['warn', 'never'],
+ 'prefer-const': 'warn',
+ 'prefer-template': 'warn',
+ },
+ },
+ },
+ {
+ plugins: {
+ 'simple-import-sort': simpleImportSort,
+ },
+ rules: {
+ 'simple-import-sort/imports': 'warn',
+ },
+ },
+ {
+ plugins: {
+ unicorn: eslintPluginUnicorn,
+ },
+ rules: {
+ ...Object.fromEntries(
+ Object.entries(eslintPluginUnicorn.configs.recommended.rules).map(([rule, level]) => [
+ rule,
+ level === 'off' ? 'off' : 'warn',
+ ]),
+ ),
+ 'unicorn/better-regex': 'warn',
+ 'unicorn/filename-case': ['warn', { cases: { kebabCase: true, pascalCase: true } }],
+ 'unicorn/prefer-global-this': 'off',
+ 'unicorn/prefer-import-meta-properties': 'warn',
+ 'unicorn/prefer-top-level-await': 'off',
+ 'unicorn/prevent-abbreviations': 'off',
+ },
+ },
+ ...pluginVue.configs['flat/recommended'],
+ {
+ rules: {
+ ...{
+ 'vue/no-v-html': 'off',
+ 'vue/one-component-per-file': 'off',
+ },
+ ...{
+ 'vue/component-name-in-template-casing': 'warn',
+ 'vue/component-options-name-casing': 'warn',
+ 'vue/custom-event-name-casing': 'warn',
+ 'vue/match-component-file-name': ['warn', { extensions: ['vue'], shouldMatchCase: true }],
+ 'vue/match-component-import-name': 'warn',
+ 'vue/no-boolean-default': 'warn',
+ 'vue/no-potential-component-option-typo': 'warn',
+ 'vue/no-useless-mustaches': 'warn',
+ 'vue/no-useless-v-bind': 'warn',
+ 'vue/require-direct-export': 'warn',
+ 'vue/require-name-property': 'warn',
+ 'vue/v-for-delimiter-style': 'warn',
+ 'vue/v-on-handler-style': ['warn', 'inline'],
+ },
+ ...{
+ 'vue/dot-notation': 'warn',
+ 'vue/eqeqeq': 'error',
+ 'vue/no-console': ['warn', { allow: ['warn', 'error'] }],
+ 'vue/no-constant-condition': 'error',
+ 'vue/no-empty-pattern': 'error',
+ 'vue/no-implicit-coercion': 'warn',
+ 'vue/no-irregular-whitespace': 'error',
+ 'vue/no-loss-of-precision': 'error',
+ 'vue/no-negated-condition': 'warn',
+ 'vue/no-sparse-arrays': 'error',
+ 'vue/no-useless-concat': 'warn',
+ 'vue/object-shorthand': 'warn',
+ 'vue/prefer-template': 'warn',
+ },
+ },
+ },
+ {
+ files: ['**/*.vue'],
+ rules: {
+ 'no-useless-assignment': 'off', // ESLint не умеет работать с этим правилом внутри
+ },
+ },
+ eslintConfigPrettier,
+];
+
+export default config;
diff --git a/packages/babel-plugin-nunjucks/package.json b/packages/babel-plugin-nunjucks/package.json
new file mode 100644
index 0000000..3c66033
--- /dev/null
+++ b/packages/babel-plugin-nunjucks/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "@advdominion/babel-plugin-nunjucks",
+ "version": "3.0.0",
+ "type": "module",
+ "main": "index.js",
+ "repository": {
+ "type": "git",
+ "url": "https://gitea.optiweb.ru/public/frontend.git"
+ },
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "nunjucks": "^3.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 12b6782..fbe9db7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5,6 +5,16 @@ __metadata:
version: 8
cacheKey: 10c0
+"@advdominion/babel-plugin-nunjucks@workspace:packages/babel-plugin-nunjucks":
+ version: 0.0.0-use.local
+ resolution: "@advdominion/babel-plugin-nunjucks@workspace:packages/babel-plugin-nunjucks"
+ dependencies:
+ nunjucks: "npm:^3.0.0"
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ languageName: unknown
+ linkType: soft
+
"@advdominion/eslint-config@workspace:*, @advdominion/eslint-config@workspace:packages/eslint-config":
version: 0.0.0-use.local
resolution: "@advdominion/eslint-config@workspace:packages/eslint-config"
@@ -1300,6 +1310,13 @@ __metadata:
languageName: node
linkType: hard
+"a-sync-waterfall@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "a-sync-waterfall@npm:1.0.1"
+ checksum: 10c0/1c7b258da2c77eb1447dcc683afb10ca3dc8880de990562ccbb7b282538aba01e910345ce9e8500c1458272c7866b85fcfa5ca8159e33550b011ab5c586ec5a4
+ languageName: node
+ linkType: hard
+
"abbrev@npm:^3.0.0":
version: 3.0.1
resolution: "abbrev@npm:3.0.1"
@@ -1470,6 +1487,13 @@ __metadata:
languageName: node
linkType: hard
+"asap@npm:^2.0.3":
+ version: 2.0.6
+ resolution: "asap@npm:2.0.6"
+ checksum: 10c0/c6d5e39fe1f15e4b87677460bd66b66050cd14c772269cee6688824c1410a08ab20254bb6784f9afb75af9144a9f9a7692d49547f4d19d715aeb7c0318f3136d
+ languageName: node
+ linkType: hard
+
"async-function@npm:^1.0.0":
version: 1.0.0
resolution: "async-function@npm:1.0.0"
@@ -1911,6 +1935,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "commander@npm:5.1.0"
+ checksum: 10c0/da9d71dbe4ce039faf1fe9eac3771dca8c11d66963341f62602f7b66e36d2a3f8883407af4f9a37b1db1a55c59c0c1325f186425764c2e963dc1d67aec2a4b6d
+ languageName: node
+ linkType: hard
+
"common-ancestor-path@npm:^1.0.1":
version: 1.0.1
resolution: "common-ancestor-path@npm:1.0.1"
@@ -4659,6 +4690,24 @@ __metadata:
languageName: node
linkType: hard
+"nunjucks@npm:^3.0.0":
+ version: 3.2.4
+ resolution: "nunjucks@npm:3.2.4"
+ dependencies:
+ a-sync-waterfall: "npm:^1.0.0"
+ asap: "npm:^2.0.3"
+ commander: "npm:^5.1.0"
+ peerDependencies:
+ chokidar: ^3.3.0
+ peerDependenciesMeta:
+ chokidar:
+ optional: true
+ bin:
+ nunjucks-precompile: bin/precompile
+ checksum: 10c0/7fe5197559b7c09972c79e2a86f9c093459b9075bc9b41134cd2bc599ae93567b53bd09d472a748edc736192d9ccd2998aa8c20cfcbe6a3fffd281f91897c888
+ languageName: node
+ linkType: hard
+
"nx@npm:>=21.5.3 < 23.0.0":
version: 22.3.3
resolution: "nx@npm:22.3.3"