Laravel 混合构建过程可扩展到许多 (50+) 主题

Laravel Mix build process scalable up to lots of (50+) themes

是否有一种标准的方式来扩展 Laravel Mix 以支持 50 多个不同前端主题的构建过程?

我只是 运行 npm run devnpm run watch 目前在我的 webpack.mix.js 文件中有四个不同的主题,并且 builds/watches 所有这些主题,但我担心当我们扩大规模时,性能会崩溃。理想情况下,我希望一次只能 build/watch 个主题,例如npm run dev --theme:some-sitenpm run watch --theme:another-site

如果我不做任何更改,我的 webpack.mix.js 最终会变成这样:

const mix = require('laravel-mix');

// Parent Theme
mix.js('resources/[parent-theme-folder]/assets/js/app.js', 'public/[parent-theme-folder]/js/')
  .sass('resources/[parent-theme-folder]/assets/scss/app.scss', 'public/[parent-theme-folder]/css/')
  ;

// Client 1
mix.js('resources/[child-theme-1-folder]/assets/js/app.js', 'public/[child-theme-1-folder]/js/')
  .sass('resources/[child-theme-1-folder]/assets/scss/app.scss', 'public/[child-theme-1-folder]/css/')
  ;
// Client 2
mix.js('resources/[child-theme-2-folder]/assets/js/app.js', 'public/[child-theme-2-folder]/js/')
  .sass('resources/[child-theme-2-folder]/assets/scss/app.scss', 'public/[child-theme-2-folder]/css/')
  ;
...etc...
// Client 47
mix.js('resources/[child-theme-47-folder]/assets/js/app.js', 'public/[child-theme-47-folder]/js/')
  .sass('resources/[child-theme-47-folder]/assets/scss/app.scss', 'public/[child-theme-47-folder]/css/')
  ;

有什么建议吗?谢谢!

--

有关我们设置的更多信息,如果有帮助...

我们正在使用 parent/child 主题包 - igaster/laravel-theme - 在一个 Laravel 项目中管理多个前端。本质上,我们有 4 种类型的网站产品,20-30 个客户都有自己的最多 4 种产品实例。他们每个人都有自己的子主题,扩展该产品的父主题以添加任何自定义布局、样式、视图等。我们认为一个 Laravel 项目比设置 20-30 个不同的项目更容易管理Laravel 每个客户的项目,尤其是在管理维护和更新方面。

根据the documentation,可以使用环境变量将参数注入LaravelMix。将它与您的 package.json 中的自定义脚本相结合,您就可以得到想要的东西。

默认package.json附带以下两个脚本(以及更多):

"scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
}

只需将您自己的脚本添加为包装器即可:

"scripts": {
    "dev": "npm run development",
    "dev:customer1": "cross-env MIX_CUSTOMER=customer1 npm run dev"
}

当然这也适用于纱线...

在您的 webpack.mix.js 中,您可以简单地查询环境变量以仅构建一个客户:

const mix = require('laravel-mix');

// Parent Theme
mix.js('resources/[parent-theme-folder]/assets/js/app.js', 'public/[parent-theme-folder]/js/')
  .sass('resources/[parent-theme-folder]/assets/scss/app.scss', 'public/[parent-theme-folder]/css/');

if (process.env.MIX_CUSTOMER === 'customer1') {
    mix.js('resources/[child-theme-1-folder]/assets/js/app.js', 'public/[child-theme-1-folder]/js/')
      .sass('resources/[child-theme-1-folder]/assets/scss/app.scss', 'public/[child-theme-1-folder]/css/');
}

if (process.env.MIX_CUSTOMER === 'customer2') {
    mix.js('resources/[child-theme-2-folder]/assets/js/app.js', 'public/[child-theme-2-folder]/js/')
      .sass('resources/[child-theme-2-folder]/assets/scss/app.scss', 'public/[child-theme-2-folder]/css/');
}

为了简化您的webpack.mix.js,您还可以在使用环境变量时执行以下操作:

const mix = require('laravel-mix');

// Parent Theme
mix.js('resources/[parent-theme-folder]/assets/js/app.js', 'public/[parent-theme-folder]/js/')
  .sass('resources/[parent-theme-folder]/assets/scss/app.scss', 'public/[parent-theme-folder]/css/');

function buildCustomerAssets(customerFolder)
{
    mix.js(`resources/${customerFolder}/assets/js/app.js', 'public/${customerFolder}/js/`)
      .sass(`resources/${customerFolder}/assets/scss/app.scss', 'public/${customerFolder}/css/`);
}

var customers = {
    'customer1': 'child-theme-1-folder',
    'customer2': 'child-theme-2-folder',
};

if (process.env.MIX_CUSTOMER) {
    var customerFolder = customers[process.env.MIX_CUSTOMER];
    buildCustomerAssets(customerFolder);
} else {
    for (const customerFolder of Object.values(customers)) {
        buildCustomerAssets(folder);
    }
}

因为你的父主题使用相同的文件夹结构,你甚至可以使用函数编译它。但所有这些只有在您的构建配置对所有客户都完全相同时才有意义。

我最终采用了 compulsivecoders article 中详细介绍的技术,但进行了一些个人调整。我不会重复他们的整篇文章并解释每一行,但我会在下面包含您复制我的设置所需的每一行代码。

--

首先,运行npm install laravel-mix-merge-manifest。如果您想在您的视图中使用 mix() 来查找您的 css/js 资产并启用缓存清除,则此部分是必需的。否则,每次 运行 npm run dev/watch/etc --theme=theme-name 它都会覆盖 mix-manifest.json 文件中的先前主题,您将得到 Laravel 找不到您的资产的错误。最后,您实际上会在主题的混合文件中使用此包。

然后,删除根目录中 webpack.mix.js 文件中的所有内容并粘贴:

// webpack.mix.js
try {
    require(`${__dirname}/webpack/webpack.${process.env.npm_config_theme}.mix.js`)
} catch (ex) {
    console.log(
        '\x1b[41m%s\x1b[0m',
        'Provide correct --theme argument to build, e.g.: `npm run watch --theme=theme1` or `npm run dev --theme=theme2`'
    )
    throw new Error('Provide correct --theme argument to build: `npm run watch --theme=theme1` or `npm run dev --theme=theme2`')
}
// ...that's it. Nothing is ever managed in this file.

我根据文章中的示例对此进行了调整。我不喜欢使用 if() 来搜索所有主题名称的数组,因为当您使用 add/remove 主题时,这是必须更新的另一件事,所以我只使用 try {} 如果找不到该主题的 webpack.mix 文件,它将输出错误。您可能会编写一些东西来查找并循环所有混音文件并一次构建所有内容,但这在我的用例中不是必需的,或者当我有这么多主题时性能不佳。

然后为每个主题创建一个/webpack/webpack.[主题].mix.js文件。我把我的放在 /webpack/ 文件夹中只是因为我不想在我的根目录中有 50 多个这样的文件。请注意,/webpack/ 文件夹在上面 webpack.mix.js 文件的第 3 行中被引用,所以如果你想在其他地方使用它,请更改该引用。这是我的一个示例,但您的示例显然会有所不同。

// /webpack/webpack.my-theme-1.mix.js
const mix = require('laravel-mix');
require('laravel-mix-merge-manifest');

mix.js('resources/my-theme-1/assets/js/app.js', 'public/my-theme-1/js/').sourceMaps().version()
   .sass('resources/my-theme-1/assets/scss/app.scss', 'public/my-theme-1/css/').sourceMaps().version()
   .mergeManifest();

注意对合并清单的两个引用。每个主题都需要这两件事。

最后,您可以通过传入 --theme=[theme-name] 参数来 运行 所有常用的构建命令,例如:

npm run dev --theme=my-theme-1
npm run watch --theme=my-theme-2
npm run prod --theme=my-parent-theme-1

我个人将我的终端和 运行 watch 在我的子主题和父主题上分开,因为我开始构建它们,但是一旦我的父主题稳定下来,我就会有观看我的儿童主题。

到目前为止一切都很好,但我愿意接受批评。感谢大家帮助我走上正确的道路。