Laravel Mix? Laravel 的前端资源编译器

file

Laravel Mix,与 Laravel Elixir 相似又完全不同。

Laravel Elixir 是 Gulp 的一个包装器。

在 Laravel 5.4 中,Elixir 已被一个名为 Mix 的新项目取代了。目标一致,但方式不同。

Mix 有什么新东西?

如果把 Elixir 和 Mix 的默认文件拿出来看看,会发现它们非常相似:

// Elixir's gulpfile.js
const elixir = require('laravel-elixir');

require('laravel-elixir-vue-2');

elixir((mix) => {
    mix.sass('app.js')
        .webpack('app.js');
});
// Mix's webpack.mix.js
const { mix } = require('laravel-mix');

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css');

从上面的代码看来,Elixir 通过一个匿名函数来调用,而 Mix 则是明确地提供源和目的地,虽写法不同二者在这里却有异曲同工之妙。

在你刚接触 Mix 的时候,你会遇到一个很大的不同之处:运行 Elixir 你要使用 gulpgulp watch,而是用 Mix 则是需要你运行 npm run devnpm run watch。 (你可以运行 npm run hot 启用模块热加载,此模式可以热加载 Vue 文件而不影响其他未变动的 assets 文件;或者运行 npm run production 将 assets 文件压缩输出)

默认文件和文件夹结构

和 Elixir 一样,默认 Sass 文件在 resources/assets/sass/app.scss 中(文件的内容是完全一样的),而默认的 JS 文件在 resources/assets/js/app.js(因为文件是完全相同的,所以想要学习更多关于 Vue 在 5.3 中的基础结构,可以查看 Matt Stauffer 写的 5.3 的前端结构 这一帖子)。

如果你深入到 app.js 中引用的 bootstrap 文件( resources/assets/js/bootstrap.js ),你会看到我们使用Axios 而不是 Vue-Resource 来设置 X-CSRF-TOKEN( Vue-Resource 在 2016 年之后将不再工作)。

如果你在 Mix 的项目上运行 npm run dev,可以看到:

file

默认情况下,我们生成的文件的位置与 Elixir 相同:public/css/app.csspublic/js/app.js

主要 Mix 方法

正如你所见,你可以轻松的使用 Mix 处理 Sass 和 JS。Sass,显而易见,运行 Sass 文件,并将其输出为 CSS。用 JS 方法支持 ECMAScript 2015 语法、编译 .vue 文件、针对生产环境压缩代码以及对 JavaScript 文件进行其他处理。

还可以用 .less 方法将 Less 编译为 CSS:

mix.less('resources/assets/less/app.less', 'public/css');

combine 方法将文件组合在一起:

mix.combine([
    'public/css/vendor/jquery-ui-one-thing.css',
    'public/css/vendor/jquery-ui-another-thing.css'
], 'public/css/vendor.css');

copy 复制文件或目录:

mix.copy('node_modules/jquery-ui/some-theme-thing.css', 'public/css/some-jquery-ui-theme-thing.css');
mix.copy('node_modules/jquery-ui/css', 'public/css/jquery-ui');

与 Elixir 不同,Source Maps 默认情况下是关闭的,可以在 webpack.mix.js 中调用以下方法来开启:

mix.sourceMaps();

默认情况下 Mix 会以系统通知的方式告知你编译结果,如果不希望它们运行,可以使用 disableNotifications() 方法禁用。

Mix.manifest.json 和 缓存清除

熟悉 Elixir 的人可能会注意到上面的输出图像有一点与 Elixir 不同:Mix 正在生成一个开箱即用的清单文件 public/mix-manifest.json。 当然,Elixir 也会生成清单文件:public/build/rev-manifest.json,与 Mix 直接生产不同,它只会在确定启用了缓存清除(版本控制)的功能时生成它。

这些清单文件是用来映射前端文件与已经版本化处理的前端文件副本,例如: /js/app.js/js/app-86ff5d31a2.js 之间的映射。有了这个文件就可以在 HTLM 用简单的引用指向该引用的版本化文件。例如 <script src ="{{ mix('js/app.js') }}">

不像 Elixir,即使你不使用缓存清除,Mix 都会生成这个文件,但它也仅仅只是一个导向地图:

{
  "/js/app.js": "/js/app.js",
  "/css/app.css": "/css/app.css"
}

对于以前使用 Elixir 的用户来说,另一个有趣的变化是:你的构建文件现在最终在正常的输出目录,而不是单独的构建目录,所以你版本化的 JS 文件,将出现在 public/js/app-86ff5d31a2.js

要在 Mix 中启用缓存清除,只需在 Mix 文件中附加 .version()

mix.js('resources/assets/js/app.js', 'public/js')
    .sass('resources/assets/sass/app.scss', 'public/css')
    .version();

这比传递实际文件名要简单得多,就像在 Elixir 中一样。

mix() 帮助

正如上面提到的,你要使用 mix() 来代替 elixir() 引用你的资源,运行方式完全相同。 但是有一点,用 Mix 的话,要删除 Laravel 模板中默认的这些引用行:

<link href="/css/app.css" rel="stylesheet">
...
<script src="/js/app.js"></script>

用下面这种方式替换它们:

<link href="{{ mix('/css/app.css') }}" rel="stylesheet">
...
<script src="{{ mix('/js/app.js') }}"></script>

记住,这个函数只是在 mix-manifest.json 中查找字符串并返回映射的构建文件。用来保证当你清除了缓存时,它懂得去加载默认的那个文件。

代码拆分

Webpack 是对许多人来说很令人兴奋的部分,因为它提供了使代码结构化的智能能力。我还没能完全弄明白 webpack 的所有功能,Mix 也没把所有功能都打包支持,例如:tree-shaking。但它确实使你的自定义代码(它可能会经常更改)与你的供应商代码(这不应该)区分,使得用户在每次推送新版本时刷新所有供应商代码的可能性更小。

要利用这个特性,你需要使用 extract() 函数,它将你定义一个给定的库或者模块集合提取到一个单独的构建文件名为 vendor.js

mix.js('resources/assets/js/app.js', 'public/js')
    .extract(['vue', 'jquery']);

在这种情况下,Mix 生成了三个文件:public/js/app.jspublic/js/vendor.js 和第三个 Webpack 特定文件 public/js/manifest.js。 为了运行顺利,得按照以下的顺序引入这三个文件:

<script src="{{ mix('/js/manifest.js') }}"></script>
<script src="{{ mix('/js/vendor.js') }}"></script>
<script src="{{ mix('/js/app.js') }}"></script>

如果清除了缓存,并且更改了应用自定义的代码, vendor.js 文件仍会缓存,也只有应用自定义的代码才会被清除缓存,这样你的网站会加载得更快。

自定义 Webpack 配置

如果你有兴趣添加自己的自定义 Webpack 配置,只需要传递你的 Webpack 配置:

mix.webpackConfig({
    resolve: {
        modules: [
            path.resolve(__dirname, 'vendor/laravel/spark/resources/assets/js')
        ]
    }
});

(上面这个例子只是从文档复制粘贴来的~ 你真的有兴趣就自己去了解哈~)

顺便一提

说点有趣的东西吧,我想这或许能在 Webpack 文件中加点什么。 如果你想只在生产环境下复制点什么,你怎么会这样做?

会这么问是因为我发现在 Node 环境对象中,我们可以用 process.env 去访问。可以检查任何值,包括系统上的任何全局环境变量。这个发现可能可以让我们去做点其他有趣的事情,比如说有条件地检查 process.env.NODE_ENV 中的值:

if (process.env.NODE_ENV == 'production') {
    mix.webpackConfig({ ... });
}

但是在阅读源代码后,我发现 NODE_ENV 不是主要的检查。相反,是用了一个带有 inProduction 标志的配置对象去做这件事情。 这个文档里没有写,因此请谨慎使用,但你可以更新 Webpack 文件顶部的导入,然后使用该配置对象:

const { mix, config } = require('laravel-mix');

if (config.inProduction) {
    mix.webpackConfig({ ... });    
}

默认依赖关系

你可以查看 package.json 并查看每个项目包含的依赖项列表。 记住,这些是由默认的 app.jsbootstrap.js 来引用的,你可以删除 app.jspackage.json 中的引用,并重新运行 npm install ,当然删除引用并不会删除源文件。

小结

Laravel Mix 是一个代替 Laravel Elixir 的构建工具。 具有与 Elixir 几乎相同的API,却是基于 Webpack 而不是 Gulp。

就写到这里吧。毕竟实践才是第一要事。

以上内容翻译改编自 Matt Stauffer 的 Laravel 5.4 新功能系列文章之 Introducing Laravel Mix (new in Laravel 5.4)

本作品采用《CC 协议》,转载必须注明作者和本文链接
Stay Hungry, Stay Foolish.
本帖由系统于 6年前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 5
Destiny

学习了

7年前 评论

seajs编译出来的有问题...诶

7年前 评论
Code_Er

楼主自定义 Webpack 配置 那个文档可以给个链接嘛 找了很多地方都找不到关于laravel-mix里面自定义的详细解说

5年前 评论

@Code_Er 建议去前端的社区了解一下

5年前 评论
Code_Er

@JokerLinly 好的谢谢

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!