Laravel 文档阅读:用 Laravel Mix 编译资产

翻译、衍生自:https://learnku.com/docs/laravel/5.5/mix

简介#

这里的编译的「资产」可以简单理解为项目中的样式表文件和 JavaScript 脚本文件。

Laravel Mix 是 Laravel 提供的前端脚本构建工具,能够用几种常用的 CSS 和 JavaScript 预处理器处理项目脚本。 它构建在 Webpack 之上,隐藏了 Webpack 底层的复杂配置,暴露出简单易用的 API,让你轻松编译前端脚本不是梦!

下面是一个例子,流畅的链式方法调用,对 JavaScript 和 Sass 这两种不同资产类型做管道处理,在一条语句内完成,非常简单:

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

如果你以前用过 Webpack,就知道它的配置是多么的复杂了,因此当你第一眼看见 Laravel Mix 的时候,你就会情不自禁的爱上她。你也并非一定要用 Laravel Mix 开发,可以选择任何你希望使用的构建工具(像 Gulp),甚至不用任何构建工具都可以。

安装 & 设置#

安装 Node#

开始用 Mix 前,必须要保证在你的机器上安装了 Node.js 和 NPM 哦。

node -v
npm -v

如果你是用 Homestead 的话,就可以省略这一步了,因为 Homestead 中包含开发 Laravel 程序所需要的一切环境。

Laravel Mix#

对,没有错,这一步就可以直接安装 Laravel Mix 了。在你刚创建的一个 Laravel 项目里,根目录配置文件 package.json 中,已经为你预设好了。

"devDependencies": {
    "axios": "^0.16.2",
    "bootstrap-sass": "^3.3.7",
    "cross-env": "^5.0.1",
    "jquery": "^3.1.1",
    "laravel-mix": "^1.0",
    "lodash": "^4.17.4",
    "vue": "^2.1.10"
}

package.json 就像是 composer.json 文件。不过前者是安装 Node 依赖包使用的,后者是安装 PHP 依赖包使用的。好,下面开始安装:

npm install

如果你是用 Windows 系统开发的,或者是用了安装在 Windows 系统上的虚拟机(VM)。你就可能需要在执行 npm install 命令的时候带上 --no-bin-links 选项:

npm install --no-bin-links

运行 Mix#

Mix 是构建在 Webpack 上的一个配置层。所以执行 Mix 任务时,需要使用 NPM 脚本命令,这些命令在 package.json 文件中定义:

// Run all Mix tasks...
npm run dev

// Run all Mix tasks and minify output...
npm run production

监听资产变化#

npm run watch 与前两条命令不同的是,它会在你的终端一直运行、监听所有相关文件的改变,一旦有文件改变,就会自动重新编译:

npm run watch

在某些情况下,这条命令对于 Webpack 不好使,它不给你重新编译的,针对这种情况,考虑使用 watch-poll 命令:

npm run watch-poll

使用样式表#

webpack.min.js 是所有资产编译的入口文件,可以把它看做是包裹了 Webpack 底层复杂配置的一个轻量的配置文件(同样是配置文件,差距就是那么大呢)。在这里面定义了链式的 Mix 任务,每个 Mix 任务就相当于是一个编译规则呢。

Less#

less 方法用来把 Less 文件编译为 CSS。下面,让我们把原本的 app.less 文件输出为 public/css/app.css 文件。

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

你可以同时调用多个 less 方法来满足项目中编译不同地方的样式文件的需要:

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

如果要自定义编译出来的 CSS 文件名,那么在第二个参数里带上文件完整路径名就 OK 了:

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

less 方法底层使用的是 Webpack 的 Less loader 插件,如果你要深度定制这个插件的配置信息,为 min.less() 传递第三个参数(对象类型)就 OK 了。

mix.less('resources/assets/less/app.less', 'public/css', {
    strictMath: true
});

Sass#

sass 方法用来把 Sass 文件编译为 CSS。它像下面这样用:

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

哎哟,不错哦,你有没有感觉跟 less 方法很像呢,确实!多次链式调用 sass 方法同时编译出多个 CSS 文件也是 OK 的:

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

有没有看到,第二个 sass 方法,我们还自定义了 CSS 输出目录,前面的 less 方法也可以这么玩啊(好吧,我不说了……)。

注意啊,sass 方法底层可不是使用 Webpack 的一个什么插件,而是直接使用了 Node.js 的 node-sass 插件。同样,如果要深入定制她的话,给她传递第三个参数就 OK 了:

mix.sass('resources/assets/sass/app.sass', 'public/css', {
    precision: 5
});

Stylus#

类似于 Less 和 Sass,stylus 方法用来把 Stylus 编译成 CSS:

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

也可以安装额外的 Stylus 插件,比如 Rupture。首先使用 npm install rupture 安装插件,然后给 mix.stylus 配置上它。

mix.stylus('resources/assets/stylus/app.styl', 'public/css', {
    use: [
        require('rupture')()
    ]
});

PostCSS#

PostCSS 是一款强大的 CSS 转换器,Laravel Mix 开箱支持它。默认,Mix 使用广受欢迎的 Autoprefixer 插件来自动添加 CSS3 第三方浏览器前缀。你也可以自由的你的应用程序中要用的任何其他插件 —— 首先,使用 NPM 安装插件,然后在 webpack.mix.js 中引用它:

mix.sass('resources/assets/sass/app.scss', 'public/css')
   .options({
        postCss: [
            require('postcss-css-variables')()
        ]
   });

纯 CSS#

如果是要把多个纯 CSS 样式文件合并成一个,就用 styles 方法:

mix.styles([
    'public/css/vendor/normalize.css',
    'public/css/vendor/videojs.css'
], 'public/css/all.css');

URL 处理#

Laravel Mix 构建在 Webpack 之上,所以需要先理解几个 Webpack 的概念。编译 CSS 时,Webpack 会重写和优化样式表里的 url() 规则。想象我们要编译的 Sass 文件里使用了相对路径引入了图片文件:

.example {
    background: url('../images/example.png');
}

注意,url() 里使用绝对路径引入图片的情况不会被处理。比如,url('/images/thing.png')url('http://example.com/images/thing.png') 就保持原样,不被处理。

默认,Laravel Mix 和 Webpack 会找到 eaxmple.png 文件,把它复制到 public/images 目录下,然后重写样式表里的 url() 规则。比如,你的 CSS 会被编译为:

.example {
  background: url(/images/example.png?d41d8cd98f00b204e9800998ecf8427e);
}

如果你不需要重写 url() 里的规则,也可以禁用它:

mix.sass('resources/assets/app/app.scss', 'public/css')
   .options({
      processCssUrls: false
   });

webpack.mix.js 中添设定了这个选项后,url() 里的规则保持原样不变。还是下面这样:

.example {
    background: url("../images/thing.png");
}

Source Maps#

编译资产时,Source Map 默认是禁用的,你可以使用 mix.sourceMaps() 方法启用它。虽然在编译时,这样会带来额外的开销,但是在你 debug 的时候非常有用。

mix.js('resources/assets/js/app.js', 'public/js')
   .sourceMaps();

使用 JavaScript#

Mix 提供了几个功能来帮助您处理 JavaScript 脚本文件,例如编译 ECMAScript 2015、模块捆绑、压缩以及合并纯 JavaScript 文件。 更棒的是,这一切不需要一丁点的自定义配置,即可直接使用:

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

这一行代码,你就使用了:

  • ES2015 语法。
  • 模块。
  • 编译 .vue 文件。
  • 生产环境下的代码压缩。

第三方提取#

把项目的脚本代码和第三方库代码合并到一起有一个缺点:很难长期缓存文件。例如,项目中单个文件代码的修改就会导致,那些第三方库代码也跟着重新编译(不管有没有改动代码),然后浏览器重新加载编译后的文件。

如果你项目中的 JavaScript 代码经常修改,你就应该考虑把第三方看库文件提取出来放在属于他们的文件里。这样一来,你项目的脚本代码的修改和重新编译,不会影响到体积较大的 vendor.js 文件。Mix 的 extract 方法就是做这个的:

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

extract 方法的接受的数组参数里,就是你最终要放到 vendor.js 文件里的所有库和模块。使用上面的逻辑编译脚本文件后,会产出以下 3 个文件:

  • public/js/mainfest.js:Webpack 运行时清单。
  • public/js/vendor.js:第三方库。
  • public/js/app.js:项目脚本代码。

为了避免 JavaScript 错误,确保按照下面的顺序加载文件:

<script src="/js/manifest.js"></script>
<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>

React#

Mix 也会自动安装 React 所需要的 Babel 插件。在你使用 mix.react() 而非 min.js()

mix.react('resources/assets/js/app.jsx', 'public/js');

在背后,Mix 会下载和引入正确的 babel-preset-react 这个 Babel 插件。

原生 JS#

类似 mix.styles() 方法,你可以使用 scripts() 方法合并和压缩任意数量的 JavaScript 文件:

mix.scripts([
    'public/js/admin.js',
    'public/js/dashboard.js'
], 'public/js/all.js');

这个方法并没有使用到 Webpack 编译 JavaScript 脚本文件。

注意,还有一个 mix.babel() 方法,它是在 mix.scripts 方法的基础上做了一些的修改,但支持 ES2015 语法的编译,而且两者的方法签名都是一样的。经过 mix.babel() 方法合并的脚本文件会经过 Babel 的编译,将任何 ES2015 代码转换为浏览器支持的原生 JavaScript 代码。

自定义 Webpack 配置#

在上面这些开箱提供的简单 API 背后,Laravel Mix 引用了一个预先配置的 webpack.config.js 文件,一般以便能使你尽快上手使用。有时,你可能需要手动修改此文件,引用特殊的加载程序或插件,或者使用 Stylus 而不是 Sass。 在这种情况下,您有两种选择:

合并自定义配置#

Mix 提供了一个有用的 webpackConfig 方法来合并、覆盖任何简短的 Webpack 配置项。这种选择比较好,因为它不需要你复制和维护一个 webpack.config.js 副本。webpackConfig 方法接收一个对象参数,你可以在里面定义任何你想要自定义的 Webpack 配置项

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

自定义配置文件#

如果你要完全自定义你的 Webpack 配置文件的话,就要把 node_modules/laravel-mix/setup/webpack.config.js 复制到你的项目根目录下,然后修改 package.json 文件里 --config 后面的配置文件路径(--config=webpack.config.js)。

如果你采用这种方式的话,未来所有在 Mix 上的更新都要手工合并到你的自定义配置文件里。

复制文件 & 目录#

copy 方法用来复制文件从一个位置到另一个位置。当你需要把 node_modules 文件夹里的文件复制到 public 下时很有用。

mix.copy('node_modules/foo/bar.css', 'public/css/bar.css');

复制整个文件夹的话,就使用 copyDirectory 方法:

mix.copyDirectory('assets/img', 'public/img');

加版本号 / 清除缓存#

许多开发者会在编译资产文件前加上时间戳或者唯一令牌号,来强制浏览器加载最新编译的脚本文件而不是使用之前的老版本。Mix 用 version 方法来解决这个问题。

version 方法会自动给编译出来的脚本文件名附加一个 hash 值,强制浏览器加载最新编译的脚本文件。

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

带版本号的脚本文件编译好后,你是不知道确切的文件名的。这是使用 Laravel 全局的 mix 方法在视图里加载正确的带版本号的脚本文件。mix 方法会自动确定正确的 hash 文件:

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

因为版本文件在开发期间不常使用,所以可以设定只在执行 npm run production 命令时才给资产文件添加版本号:

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

if (mix.inProduction()) {
    mix.version();
}

浏览器同步加载#

BrowserSync 可以用来自动监听文件改变,在不需要手工刷新的情况下,在浏览器中同步加载更新的文件内容。这时,你要使用 mix.browserSync() 方法做到:

mix.browserSync('my-domain.dev');

// Or...

// 更多配置项参考:https://browsersync.io/docs/options
mix.browserSync({
    proxy: 'my-domain.dev'
});

browserSync 方法接收的参数可以是一个(代理)字符串或者是(BrowserSync 配置)对象。接下来,当你使用 npm run watch 命令后,每当你修改一个脚本或者 PHP 文件,在浏览器中的页面都会立即更新。

环境变量#

我们可以向 Mix 中注入环境变量,这是通过在 .env 文件中设定以 MIX_ 作为前缀的 Key 做到的:

MIX_SENTRY_DSN_PUBLIC=http://example.com

.env 文件中,定义好变量后,就可以通过 process.env 对象获得这个变量。如果你在 watch 时改变了这个值,是需要停止、然后重启 watch 才能让变化后的变量值生效。

process.env.MIX_SENTRY_DSN_PUBLIC

通知#

如果可用的话,Mix 会在每次编译任务完成后,自动操作系统级别的通知, 给你即时的反馈说编译是否成功了。 不过,如果你希望停用这些通知 —— 比如,你遇到过在你的生产环境的服务器上这可能会再一次触发 Mix,这时,就需要用 disableNotifications 方法禁用它了。

 mix.disableNotifications();
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由 Summer 于 7年前 加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。