概览
API
常用插件
高级配置
基本示例
larave-mix是位于webpack顶层的一个简洁的配置层,在80%的的情况下使用laravel mix会使操作变的非常简单。尽管webpack非常的强大,但大部分人都认为webpack的学习曲线非常陡峭。但是如果你不必用再担心这些了呢?
看一下基本的webpack.mix.js文件,让我们想象一下我们现在只需要编译javascript(ES6)和sass文件:
let mix = require('laravel-mix'); mix.sass('src/app.sass', 'dist') .js('src/app.js', 'dist');
怎么样,简单吗?
1. 编译sass文件, ./src/app.sass到 ./dist/app.css
2. 打包在./src/app.js的所有js(包括任何依赖)到 ./dist/app.js。
使用这个配置文件,可以在命令行触发webpack指令:node_modules/bin/webpack
在开发模式下,并不需要压缩输出文件,如果在执行webpack的时候加上环境变量:export NODE_ENV=production && webpack,文件会自动压缩
less
但是如果你更喜欢使用Less而不是Sass呢?没问题,只要把mix.sass()换成mix.less()就OK了。
使用laravel-mix,你会使发现大部分webpack任务会变得更又把握
安装
尽管laravel-mix对于laravel使用来说最优的,但也能被用于任何其他的应用。
laravel项目
laravel已经包含了你所需要的一切,简易步骤:
1. 安装laravel
2. 运行 npm install
3. 看一下你的webpack.mix.js ,然后就done了
你可以在命令行运行 npm run watch 来监视你的前段资源改变,然后重新编译。
注:在项目根目录下并没有webpack.config.js配置文件,laravel默认指向根目录下的配置文件。如果你需要自己配置它,你可以把它拷贝到根目录下,同时修改package.json里的npm脚本: cp node_modules/laravel-mix/setup/webpack.config.js ./
.
独立项目
首先使用npm或者yarn安装laravel-mix,然后把示例配置文件复制到项目根目录下
mkdir my-app && cd my-app npm init -y npm install laravel-mix --save-dev cp -r node_modules/laravel-mix/setup/** ./
现在你会有如下的目录结构
- node_modules/
- package.json
- webpack.config.js
- webpack.mix.js
laravel-mix 包括两个核心组件
- webpack.mix.js: 这是你在webpack上层的配置文件,大部分时间你需要修改的是这个文件
- webpack.config.js: 这是传统的webpack配置文件,只有在有更高级的配置需求时才需要更改
打开你的webpack.mix.js文件:
let mix = require('laravel-mix'); mix.js('src/app.js', 'dist') .sass('src/app.scss', 'dist');
注意源文件的路径,然后创建匹配的目录结构(你也可以改成你喜欢的结构)。现在都准备好了,在命令行运行node_modules/.bin/webpack 编译所有文件,然后你将会看到:
- dist/app.css
- dist/app.js
- dist/mix-manifest.json(你的asset输出文件,稍后讨论)
干得漂亮!现在可以干活了。
NPM Scripts
把下面的npm脚本添加到你的package.json文件中可以让你的工作更快,laravel安装的时候已经包含了这个东西了
"scripts": { "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules", "watch": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules", "hot": "cross-env NODE_ENV=development webpack-dev-server --inline --hot", "production": "cross-env NODE_ENV=production webpack --progress --hide-modules" }
laravel工作流程
我们先回顾一下通用的工作流程以便你能在自己的项目上采用
1 . 安装laravel
laravel new my-app
2 . 安装Node依赖
npm install
3 . 配置webpack.mix.js
这个文件所有前端资源编译的入口
let mix = require('laravel-mix'); mix.js('resources/assets/js/app.js', 'public/js'); mix.sass('resources/assets/sass/app.scss', 'public/css');
默认会启用ES2015模块绑定,就行sass编译一样。
4 . 编译
用如下指令编译
node_modules/.bin/webpack
也可以使用package.json 里的npm脚本:
npm run dev
然后会看到编译好的文件:
- ./public/js/app.js
- ./public/css/app.css
监视前端资源更改:
npm run watch
laravel装载了一个./resources/assets/js/components/Example.vue文件,do它,编译完成后会有一个系统通知。
5 . 修改视图
laravel自带一个欢迎页面,我们可以用这个来做示例,修改一下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Laravel</title> <link rel="stylesheet" href="{{ mix('css/app.css') }}"> </head> <body> <div id="app"> <example></example> </div> <script src="{{ mix('js/app.js') }}"></script> </body> </html>
刷新页面,干得漂亮!
6 . 热加载
当我们修改了已个vue组件的时候可以立即在浏览器看到他的变化而不是需要手动去刷新是非常酷的,更酷的是,刷新不会重置我们组件的状态。HMR来拯救你了!
返回命令行,Ctrl+c强制结束webpack监视器,然后输入:
npm run hot
“hot”表示HMR(Hot module replacement),这个指令是你激活热加载唯一需要做的事情
刷新浏览器,然后修改./resources/assets/js/components/Example.vue文件,一旦你点击保存,浏览器就会立马有反应,酷不酷!
Larave Mix vs. Laravel Elixir
mix和elixir有哪些不同呢?
你可能已经知道一个叫做laravel elixir的工具已经存在一段时间了(也是我们写的), laravel mix 是它的升级版,尽管他们的API是几乎一样的,但还有少数关键的不同你需要知道一下,如果你要替换他们的话。
1 . laravel mix 是建立在webpack的顶层,而不是Gulp
最重要的变化当然是我们把底层实现用webpack替代了gulp,这样带来的结果是不仅更健壮,更灵活,而且更简单,更可配置(你所需要的)的代码。请注意一下所有的laravel elixir插件都使用gulp,因为laravel mix 使用的是webpack,所以laravel elixir的插件在这里都不能用了,那就是为什么我们改了名字,避免大家蒙圈。另一方面,laravel mix不需要插件,所以你可以自由的编写webpack.config.js。
2 . gulpfile.js变成webpack.mix.js
因为laravel mix 建立在webpack上,所以安装laravel的时候你并不能找到gulpfile.js,而是:
- webpack.mix.js 这个文件等同于gulpfile.js,实际上你会发现API几乎是一样的
3 . webpack 不是一个通常意义上的任务构建工具 ,like gulp
对于一般的任务,gulp是非常nice的,移动文件,压缩脚本,编译js,还能版本化特定文件,然而,webpack只是一个JavaScript入口,在这里,你可以选择多种编译方式或者插件。这是一个很重要的区别。
话虽然是这么说,我们还是要给你介绍一些跟webpack模块无关的操作来合并多个文件,或者压缩样式表,这意味着,mix.copy(),mix.combine(),mix.minify() 仍然是可以用的
例如:在laravel elixir下,你可能会使用mix.version('./public/some/random/files.js') ,它会给文件名附加hash值。但在laravel mix下,你只需要简单的调用mix.version()就行了,工具会自动的版本化所有的关联文件。
4.更灵活
因为我们现在使用webpack,会有一些新的功能,例如mix.extract(['vendor', 'libs']), 它会把所有指定的第三方库拆分成独立的文件,为了长期缓存。
常见问题
laravel-mix必须在laravel下使用吗?
不,在laravel下使用使最好的,但也可以用在别的任何项目
我的代码没有压缩
只有在node环境变量为生产环境时才会被压缩,这样会加速编译过程,但在开发过程中是不必要的,下面是在生成环境下运行webpack的示例
export NODE_ENV=production && webpack --progress --hide-modules
强烈推荐你把下面的npm脚本添加到你的package.json文件中,注意laravel已经包括了这些了
"scripts": { "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules", "watch": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules", "hot": "cross-env NODE_ENV=development webpack-dev-server --inline --hot", "production": "cross-env NODE_ENV=production webpack --progress --hide-modules" },
我使用的是VM,webpack不能检测到我的文件变化
如果你在VM下执行 npm run dev,你会发现webpack并不能监视到你的文件改变。如果这样的话,修改一下你的npm脚本,使用--watch-poll和--watch标签,像这样:
"scripts": { "watch": "NODE_ENV=development webpack --watch --watch-poll", }
如果你还是有问题,去这儿溜达溜达吧。
为什么在我的css文件里显示图片在node_modules里找不到
你可能用的是相对路径,但是在的resources/assets/sass/app.css里并不存在:
body { background: url('../img/example.jpg'); }
当引用相对路径的时候,会根据当前文件的路径来搜索,同样的,webpack会首先搜索resources/assets/img/example.jpg,如果找不到,会继续搜索文件位置,包括node_modules,如果还找不到,就报错:
ERROR Failed to compile with 1 errors This dependency was not found in node_modules:
有两个解决办法:
1 . 让resources/assets/img/example.jpg能找得到就行了,就是把文件放这儿。
2 . 编译css的时候添加下面的选项,禁用css的url处理:
mix.sass('resources/assets/sass/app.scss', 'public/css') .options({ processCssUrls: false });
这对于一些文件This is particularly useful for legacy projects where your folder structure is already exactly as you desire.完全符合你的要求的遗留项目是非常有用的。
我不想把mix-manifest.json文件放在项目根目录下
如果你没有使用laravel,你的mix-manifest.json文件会被放到项目根目录下,如果你不喜欢的话,可以调用mix.setPublicPath('dist/'),然后manifest文件就会被放到dist目录下。
怎样使用webpack自动加载模块
webpack 使用ProvidePlugin插件加载一些需要的模块,常用的一个例子就是加载jQuery:
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }); // in a module $('#item'); // <= just works jQuery('#item'); // <= just works
//$和jQuery被自动设置为‘jQuery’的出口
当laravel-mix自动加载模块的时候(像上面说的那样),你如果想禁用(传一个空对象)或者用你自己的模块覆盖它,可以调用mix.autoload()方法:
mix.autoload({ jquery: ['$', 'window.jQuery', 'jQuery'], // more than one moment: 'moment' // only one })
怎样手动添加CoffeeScript编译器
非常简单!你只需要在webpack.mix.js里调用mix.webpackConfig()方法就可以了,它会自动和mix的默认配置合并。
// npm install coffee-loader coffee-script
mix.js('resources/assets/js/app.coffee', 'public/js') .webpackConfig({ module: { rules: [ { test: /\.coffee$/, loader: 'coffee-loader' } ] } });
API
Javascript
mix.js(src|[src], output)
简单的一行代码,larave mix可以执行很多重要的操作
- ES2015模块编译
- 创建并且编译vue组件(通过vue-loader)
- 模块热替换(HMR)
- Tree-shaking打包技术,webpack2里新增的(移除无用的库)
- 提取和拆分vendor库(通过mix.extract方法), 使长期缓存变的容易
- 自动版本化(文件哈希),通过mix.version()
用法
let mix = require('laravel-mix'); // 1. 单个文件 mix.js('src/app.js', 'dist/app.js'); // 2. 多个文件编译成一个文件 mix.js([ 'src/app.js', 'src/another.js' ], 'dist/app.js'); // 3. 编译多个文件 mix.js('src/app.js', 'dist/') .js('src/forum.js', 'dist/');
laravel 示例
考虑到典型的laravel默认安装的时候会把入口定位在 ./resources/assets/js/app.js,所以我们先准备一个webpack.mix.js把app.js编译到 ./public/js/app.js。
let mix = require('laravel-mix'); mix.js('resources/assets/js/app.js', 'public/js');
现在上面所有的项你都可以用了,只需要调用一个方法。
在命令行调用npm run dev 执行编译。
Vue 组件
laravel mix 包罗万象,支持vue组件编译,如果你不使用vue的话,可以忽略这块。
单文件组件是vue最重要的特征。在一个文件里为一个组件定义模板,脚本,样式表。
./resources/assets/js/app.js
import Vue from 'vue'; import Notification from './components/Notification.vue'; new Vue({ el: '#app', components: { Notification } });
在上面,我们导入了vue(首先你需要执行npm install vue --save-dev安装vue),然后引入了一个叫Notification的vue组件并且注册了root vue实例。
./resources/asset/js/components/Notification.vue
<template> <div class="notification"> {{ body }} </div> </template> <script> export default { data() { return { body: 'I am a notification.' } } } </script> <style> .notification { background: grey; } </style>
如果你了解vue,这些你都会很熟悉,继续。
./webpack.mix.js
let mix = require('laravel-mix');
mix.js('resources/assets/js/app.js', 'public/js');
执行npm run dev 编译文件,这样就简单的创建了一个HTML文件,引入./js/app.js 文件,然后在浏览器里查看吧!
React 支持
laravel mix 也装载了基本的react支持,只要把mix.js()改成mix.react()并且使用相同的参数。在底层,mix会引用react需要的任何babel插件。
mix.react('resources/assets/js/app.jsx', 'public/js/app.js');
当然,你仍然需要使用npm安装react和reactDOM,不过要注意小心行事。
代码分离
mix.js(src, output) .extract(['any', 'vendor', 'library']);
把所有的js都打包成一个文件会伴随着潜在的风险:每次更新项目中就算很小的一部分都需要破坏所有用户的缓存,这意味着你的第三方库需要重新被下载和缓存。这样很不好。
一个解决的办法是分离或者提取你的库文件。
- 应用代码:app.js
- vendor库:vendor.js
- Manifest(webpack runtime): manifest.js
mix.extract(['vue', 'jquery']);
extract方法接受一个你想要从打包文件里提取出的库的数组,使用这个方法,Vue和jQuery的源代码都会被放在vendor.js里。如果在未来你需要对应用代码做一些微小的变动,并不会对大的vendor库产生影响,它们依然会留在长期缓存。
一旦执行webpack打包文件,你会发现三个新的文件,你可以在HTML页面引用它们。
<script src="/js/manifest.js"></script> <script src="/js/vendor.js"></script> <script src="/js/app.js"></script>
实际上,我们付出了一些HTTP请求的代价(就是会多请求几次)来换取长期缓存的提升。
Manifest文件是什么
webpack编译的时候会有一些run-time代码协助其工作。如果没有使用mix.extract(),这些代码你是看不到的,它会在打包文件里,然而,如果我们分离了代码并且允许长期缓存,在某些地方就需要这些run-time代码,所以,mix会把它提取出来,这样一来,vendor库和manifest文件都会被缓存很长时间。
浏览器自动刷新
BrowserSync能让浏览器实时的,快速的响应您的文件的更改 --完全不需要手动刷新。你可以调用mix.browserSync()方法来开启这个功能:
mix.browserSync('my-domain.dev'); // Or: // https://browsersync.io/docs/options/ mix.browserSync({ proxy: 'my-domain.dev' })
参数可以传字符串,也可以传对象。你声明的域名作为proxy是非常重要的,Browsersync将包裹你的虚拟主机(webpack dev server)使用代理网址查看您的网站。
Hot Module Replacement
laravel mix对模块热替换提供了无缝的支持。
模块热替换(或者叫热加载),意思就是当javascript改变刷新页面的时候可以维持组件的状态,例如现在有一个计数器,按一下按钮,计数器会加1,想象一下你点了很多次然后修改一下组件的相关文件,浏览器会实时的反映出你所做出的更改而保持计数器不变,计数器不会被重置,这就是热加载的意义最在。
在laravel里的用法
看一下laravel里的package.json文件,在scripts模块,你可以看到:
"scripts": { "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules", "watch": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules", "hot": "cross-env NODE_ENV=development webpack-dev-server --inline --hot", "production": "cross-env NODE_ENV=production webpack --progress --hide-modules" }
注意一下hot指令,这个地方就是你所需要的,在命令行执行npm run hot会启动一个node服务器并且监视你的bundle文件,接下来,在浏览器打开你的laravel应用,一般应该是http://my-app.dev。
在laravel应用里使用热加载很重要的一点是要保证所有的脚本资源引用的是前面启动的node服务器的url:http://localhost:8080,现在你可以手动更新你的HTML\Blade文件了:
<body> <div id="app">...</div> <script src="http://localhost:8080/js/bundle.js"></script> </body>
假设你有一些组件,尝试在浏览器里更改他们的状态,然后更新他们的模板文件,你可以看到浏览器会立刻反应出你的更新,但是状态并没有被改变。
但是,在开发部署环境下手动更新url会是一个负担,所以,laravel提供了一个mix()方法,他会动态的构建js或者样式表的引用,然后输出。上面的代码因此可以修改成:
<body> <div id="app"></div> <script src="{{ mix('js/bundle.js') }}"></script> </body>
当你执行npm run hot的时候,这个方法会把http://localhost:8080设置为base url,当你运行npm run dev或者npm run pro的时候,它会使用你根目录的地址。
在spa里的用法
laravel mix包含了流行的vue-loader包,这意味着,如果是单页应用,你什么都不需要做,它是开包即用的。