[譯] Laravel-mix 中文文件

imvkmark發表於2018-05-27

映象地址 : https://segmentfault.com/a/1190000015049847
原文地址: Laravel Mix Docs

概覽

基本示例

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 檔案 ,就可以開始使用了.

你可以在命令列執行 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/webpack.mix.js ./

現在你會有如下的目錄結構

node_modules/
package.json
webpack.mix.js

webpack.mix.js 是你在webpack上層的配置檔案,大部分時間你需要修改的是這個檔案

首先看下 webpack.mix.js 檔案

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

mix.js('src/app.js', 'dist')
   .sass('src/app.scss', 'dist')
   .setPublicPath('dist');

注意原始檔的路徑,然後建立匹配的目錄結構(你也可以改成你喜歡的結構)。現在都準備好了,在命令列執行 node_modules/.bin/webpack 編譯所有檔案,然後你將會看到:

  • dist/app.css
  • dist/app.js
  • dist/mix-manifest.json(你的asset輸出檔案,稍後討論)

幹得漂亮!現在可以幹活了。

NPM Scripts

把下面的npm指令碼新增到你的 package.json 檔案中可以加速你的工作操作.,laravel安裝的時候已經包含了這個東西了

"scripts": {
    "dev": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "hot": "NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  }

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');

預設會啟用 JavaScript ES2017 + 模組繫結,就行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 檔案,執行完成後會有一個系統通知。

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>

重新整理頁面,幹得漂亮!

常見問題

laravel-mix必須在laravel下使用嗎?

不,在laravel下使用使最好的,但也可以用在別的任何專案

我的程式碼沒有壓縮

只有在node環境變數為生產環境時才會被壓縮,這樣會加速編譯過程,但在開發過程中是不必要的,下面是在生成環境下執行webpack的示例

export NODE_ENV=production && webpack --progress --hide-modules

強烈推薦你把下面的npm指令碼新增到你的package.json檔案中,注意laravel已經包括了這些了

"scripts": {
    "dev": "NODE_ENV=development webpack --progress --hide-modules",
    "watch": "NODE_ENV=development webpack --watch --progress --hide-modules",
    "hot": "NODE_ENV=development webpack-dev-server --inline --hot",
    "production": "NODE_ENV=production webpack --progress --hide-modules"
},

我使用的是VM,webpack不能檢測到我的檔案變化

如果你在VM下執行 npm run dev,你會發現 webpack 並不能監視到你的檔案改變。如果這樣的話,有兩種方式來解決這個

  1. 配置 webpack 檢測檔案系統的變化, 注意:檢測檔案系統是資源密集型操作並且很耗費電池的使用時長.
  2. 轉發檔案通過使用類似於 vagrant-fsnotify 之類的東西將通知傳送給VM。注意,這是一個 只有 Vagrant 才有的外掛。

檢測 VM 檔案系統變化, 修改一下你的 npm 指令碼,使用 --watch-poll--watch 標籤,像這樣:

"scripts": {
    "watch": "NODE_ENV=development webpack --watch --watch-poll",
}

推送檔案改動到 VM, 在主機安裝 vagrant-fsnotify

vagrant plugin install vagrant-fsnotify

現在你可以配置 vargrant 來使用這個外掛, 在 Homestead 中, 在你的 Homestead.yaml 檔案類似於這樣

folders:
    -
        map: /Users/jeffrey/Code/laravel
        to: /home/vagrant/Code/laravel
        options:
            fsnotify: true
            exclude:
                - node_modules
                - vendor

一旦你的 vagrant 機器啟動, 只需要在主機上執行 vagrant fsnotify 把檔案的改動推送到 vm 上, 然後在 vm 內部執行 npm run watch 就能夠檢測到檔案的改動了.

如果你還是有問題,去這兒溜達溜達吧

為什麼在我的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
   });

他對老專案特別有用,因為你的資料夾結構已經完全建立好了。

我不想把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
// $ is automatically set to the exports of module "jquery"

當laravel-mix自動載入模組的時候(像上面說的那樣),你如果想禁用(傳一個空物件)或者用你自己的模組覆蓋它,可以呼叫 mix.autoload() 方法:

mix.autoload({
  jquery: ['$', 'window.jQuery', 'jQuery'], // more than one
  moment: 'moment' // only one
});

為什麼我看到一個 "Vue packages version mismatch"錯誤

如果, 更新你的依賴, 你有以下編譯失敗的資訊

Module build failed: Error:

Vue packages version mismatch:

* vue@2.5.13
* vue-template-compiler@2.5.15

這意味著你的 vuevue-template-compiler 依賴不同步, 每一個 Vue 的更新, 版本號必須是相同的. 更新來修復這個錯誤

npm update vue

// or

npm install vue@2.5.15

排障

我在更新/安裝 mix 時候出現錯誤

不幸的是,你的依賴項可能沒有正確安裝的原因有無數個。一個常見的根本原因是安裝了老版本的Node(node -v) 和 npm (npm -v)。第一步,訪問 http://nodejs.org 並更新它們。

否則,它通常與需要刪除的錯誤鎖檔案有關。讓這一系列命令嘗試從頭開始安裝一切

rm -rf node_modules
rm package-lock.json yarn.lock
npm cache clear --force
npm install

為什麼 webpack 不能找到我的 app.js 條目檔案?

如果你遇到這樣的失敗資訊……

These dependencies were not found:

* /Users/you/Sites/folder/resources/assets/js/app.js

... 你可能使用 npm 5.2 (npm -v) 這個版本。這個版本引入了一個導致安裝錯誤的錯誤。該問題已被在 npm 5.3 修復。請升級,然後重新安裝

rm -rf node_modules
rm package-lock.json yarn.lock
npm cache clear --force
npm install

API

Javascript

mix.js(src|[src], output)

簡單的一行程式碼,larave mix可以執行很多重要的操作

  • ES2017+ 模組編譯
  • 建立並且編譯vue元件(通過 vue-loader)
  • 模組熱替換(HMR)
  • Tree-shaking打包技術,webpack2裡新增的(移除無用的庫)
  • 提取和拆分 vendor 庫(通過mix.extract()方法), 使長期快取變的容易
  • 自動版本化(檔案雜湊),通過 mix.version()

用法

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

// 1. A single src and output path.
mix.js('src/app.js', 'dist/app.js');

// 2. For additional src files that should be
// bundled together:
mix.js([
    'src/app.js',
    'src/another.js'
], 'dist/app.js');

// 3. For multiple entry/output points:
mix.js('src/app.js', 'dist/')
   .js('src/forum.js', 'dist/');

laravel 示例

考慮到典型的laravel預設安裝的時候會把入口定位在 ./resources/assets/js/app.js,所以我們先準備一個 webpack.mix.jsapp.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 檔案都會被快取很長時間。

瀏覽器自動重新整理

mix.browserSync('my-site.test');

BrowserSync 能自動監控檔案變動並且把你的變化通知瀏覽器, -- 完全不需要手動重新整理。你可以呼叫 mix.browserSync() 方法來開啟這個功能:

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

// Or:

// https://browsersync.io/docs/options/
mix.browserSync({
    proxy: 'my-domain.test'
})

引數可以傳字串(proxy),也可以傳物件(BrowserSync 設定)。你宣告的域名作為 proxy 是非常重要的,Browsersync 將通過代理網址來輸出到你的虛擬主機(webpack dev server).

其他選項可以從 Browsersync Documentation

現在, 啟動 dev server (npm run watch), 並進行下一步操作吧.

模組熱替換

laravel mix對模組熱替換提供了無縫的支援。

模組熱替換(或者叫熱載入),意思就是當 javascript 改變重新整理頁面的時候可以維持元件的狀態,例如現在有一個計數器,按一下按鈕,計數器會加1,想象一下你點了很多次然後修改一下元件的相關檔案,瀏覽器會實時的反映出你所做出的更改而保持計數器不變,計數器不會被重置,這就是熱載入的意義最在。

在laravel裡的用法

Laravel 和 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.test

在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>

調整之後,Laravel 將為你做這項工作。如果執行 npm run hot 以啟用熱重載入,則該函式將設定必要的 http://localhost:8080 作為 URL。相反,如果您使用 npm run devnpm run pro,它將使用域名作為基準 url。

在Https 中使用
如果你在 HTTPS 連線上開發你的應用,你的熱重載入指令碼和樣式也必須通過HTTPS服務。要實現這一點,可以將 -—https 標誌新增到 package.json 中的熱選項命令中。

"scripts": {
    "hot": "NODE_ENV=development webpack-dev-server --inline --hot --https",
}

通過上面的設定,webpack-dev-server 將會生成一個自簽名證照。如果你希望使用自己的證照,可以使用以下設定:

 "hot": "NODE_ENV=development webpack-dev-server --inline --hot --https --key /path/to/server.key --cert /path/to/server.crt --cacert /path/to/ca.pem",

現在在你的 Html/Blade 檔案中可以使用

<script src="https://localhost:8080/js/bundle.js"></script>

或者

<script src="{{ mix('js/bundle.js') }}"></script>

在spa裡的用法

laravel mix包含了流行的 vue-loader 包,這意味著,如果是單頁應用,你什麼都不需要做,它是開箱即用的。

版本化

mix.js('src', 'output')
   .version([]);

為了幫助長期快取,Laravel Mix 提供了 mix.version() 方法,它支援檔案雜湊。比如app.js?id=8e5c48eadbfdd5458ec6。這對清除快取很有用。假設你的伺服器自動快取了一年的指令碼,以提高效能。這很好,但是,每當您對應用程式程式碼進行更改時,需要一些方法來告訴使用者更新快取, 這通常是通過使用查詢字串或檔案雜湊來完成的。

啟用了版本控制之後,每次程式碼更改時,都會生成一個新的雜湊查詢字串檔案。看以下webpack.mix.js 檔案

編譯後,你會在 mix-manifest.json 檔案看到 /css/app.css?id=5ee7141a759a5fb7377a/js/app.js?id=0441ad4f65d54589aea5。當然,你的特定雜湊將是唯一的。每當你調整 JavaScript 時,編譯後的檔案將會收到一個新的雜湊名稱,這將有效地破壞快取,一旦被推到生產環境中。

舉個例子,試試 webpack --watch,然後修改一下你的 JavaScript。你將立即看到一個新生成的打包檔案和樣式表。

匯入版本檔案

這就引出了一個問題:如果名稱不斷變化,我們如何將這些版本化的指令碼和樣式表包含到HTML中呢?是的,這很棘手。答案將取決於你構建的應用程式的型別。對於SPA,你可以動態地讀取 Laravel Mix生成的 manifest.json 檔案,提取資料檔名(這些名稱將被更新,以反映新的版本檔案),然後生成HTML。

Laravel 使用者

對於 Laravel 專案,一個解決方案是開箱即用的。只需呼叫全域性 mix() 函式,就完成了!我們將計算出匯入的適當檔名。這裡有一個例子:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>App</title>
        <link rel="stylesheet" href="{{ mix('css/app.css') }}">
    </head>
    <body>
        <div id="app">
            <h1>Hello World</h1>
        </div>

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

將未雜湊的檔案路徑傳遞給 mix() 函式,然後在後端,我們將弄清楚應該匯入哪個指令碼或樣式表。請注意,你可能/應該使用這個函式,即使沒有對檔案進行版本控制。

版本化附加檔案

mix.version() 將自動生成編譯後的JavaScript、Sass/Less或合併檔案。但是,如果你還希望將額外的檔案作為構建的一部分,簡單地傳遞路徑或路徑陣列,就像這樣:

mix.version(['public/js/random.js']);

現在,我們會版本化任何相關的編譯檔案,但是我們還會附加一個查詢字串,public/js/random.js?{hash},並更新 mix-manifest.json 檔案。

Css 前處理器

mix.sass('src', 'output', pluginOptions);
mix.standaloneSass('src', 'output', pluginOptions); // Isolated from Webpack build.
mix.less('src', 'output', pluginOptions);
mix.stylus('src', 'output', pluginOptions);
mix.postCss('src', 'output', [ require('precss')() ])

一個單一的方法呼叫允許你編譯你的 Sass,Less,或 Stylus 檔案,同時自動應用 CSS3 字首。

雖然 webpack 可以將所有CSS直接插入到繫結的JavaScript中,但Laravel Mix會自動執行必要的步驟,將其提取到你想要的輸出路徑中。

多構建

如果你需要編譯多個頂級檔案,你可以根據需要呼叫 mix.sass()(或任何一個前處理器變體). 對於每個呼叫,webpack 將輸出一個包含相關內容的新檔案。

mix.sass('src/app.scss', 'dist/') // creates 'dist/app.css'
   .sass('src/forum.scss', 'dist/'); // creates 'dist/forum.css'

例子

讓我們看一個例子

webpack.mix.js

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

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

./resources/assets/sass/app.sass

$primary: grey

.app
    background: $primary

Tip : 對於 Sass 編譯, 你可以使用 .sass.scss 語法

像往常一樣執行 npm run webpack 進行編譯. 你會發現 ./public/css/app.css 檔案包含

.app {
  background: grey;
}

外掛選項

編譯的時候, Laravel Mix 的首先是去分別的呼叫 Node-Sass, Less,和 Slylus 來編譯你的 Sass, Less 檔案。有時,你可能需要重寫我們傳遞給它們的預設選項。可以將它們作為第三個引數提供給 mix.sass(), mix.less()mix.stylus()

Stylus 外掛
如果使用 Stylus, 你可能希望安裝額外的外掛,比如 Rupture 。執行 npm install rupture 來安裝這個外掛,然後在你的 mix.stylus() 中呼叫, 例如:

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

如果希望更深一步,並且在全域性中自動匯入外掛,您可以使用 import 選項。這裡有一個例子:

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

就是這個樣子滴!

CSS url() 重寫

一個關鍵的 webpack 概念是,它將重寫你的樣式表中的任何 url()。雖然這可能最初聽起來很奇怪,但它是一項非常強大的功能。

一個例子

假設我們想要編譯一些Sass,其中包含一個影像的相對url。

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

提示:url()的絕對路徑將被排除在url重寫之外。因此,url('/images/thing.png')url('http://example.com/images/thing.png') 將不會被更改。

注意,這裡說的是相對URL? 預設情況下,Laravel Mix 和 webpack 將會找到 thing.png ,將其複製到 public/images 資料夾中,然後在生成的樣式表中重寫 url()。因此,編譯的CSS將是:

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

這也是 webpack 的一個很酷的特性。然而,它確實有一種傾向,讓那些不理解 webpack 和 css-loader 外掛如何工作的人感到困惑。你的資料夾結構可能已經是您想要的了,而且你希望不要修改那些url()。如果是這樣的話,我們確實提供了一個覆蓋方式:

mix.sass('src/app.scss', 'dist/')
   .options({
      processCssUrls: false
   });

把這個加上你的 webpack.mix.js 檔案中,我們將不再匹配 url() 或複製資源到你的公共目錄。因此,編譯後的CSS將與你輸入時一樣:

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

這樣的好處是,當禁用url處理時,您的 Webpack, Sass 編譯和提取可以更快地編譯。

PostCSS 外掛

預設情況下,Mix 將通過流行的 Autoprefixer PostCSS plugin 將所有的CSS檔案連線起來。因此,你可以自由使用最新的CSS 3語法,並理解我們將自動應用任何必要的瀏覽器字首。在大多數情況下,預設設定應該就可以,但是,如果你需要調整底層的自動修復程式配置,那麼如下所示:

mix.sass('resources/assets/sass/app.scss', 'public/css')
   .options({
        autoprefixer: {
            options: {
                browsers: [
                    'last 6 versions',
                ]
            }
        }
   });

另外,如果你想完全禁用它——或者依賴一個已經包含 自動字首的PostCSS外掛:

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

但是,你可能想要在構建中應用額外的PostCSS外掛。木問題, 只需在NPM中安裝所需的外掛,然後在 webpack.mix.js 檔案中引用,如下所示:

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

完成了!現在可以使用和編譯自定義CSS屬性(如果這是您的東西)。例如,如果 resources/assets/sass/app.scss 包含…

:root {
    --some-color: red;
}

.example {
    color: var(--some-color);
}

編譯完成將會是

.example {
  color: red;
}

PostCss 不適用 Sass/Less

或者,如果你更喜歡跳過 Sass/Less/Stylus 編譯步驟,而是使用 PostCSS,你可以通過mix.postCss() 方法來完成。

mix.postCss('resources/assets/css/main.css', 'public/css', [
   require('precss')()
]);

請注意,第三個引數是應該應用於你構建的 postcss 外掛的陣列。

獨立Sass構建

如果你不希望 Mix 和 Webpack 以任何方式處理你的 Sass 檔案,你可以使用mix.standaloneSass(),這將大大改善你應用程式的構建時間。請記住:如果你選擇了這條路線,Webpack 不會觸及你的 CSS。它不會重寫 url,複製資源(通過 file-loader),或者應用自動影像優化或CSS清理。如果這些特性對於你的應用程式來說是沒有必要的,那麼一定要使用這個選項而不是mix.sass()

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

注意:如果你正在使用 standaloneSass,在使用 npm run watch 進行檔案更改時,你將需要使用下劃線來字首匯入的檔案,以將它們標記為依賴檔案(例如,_header.scss _alert.scss)。如果不這樣做,將導致Sass編譯錯誤和/或額外的CSS檔案。

檔案複製

mix.copy(from, to);
mix.copy('from/regex/**/*.txt', to);
mix.copy([path1, path2], to);
mix.copyDirectory(fromDir, toDir);

有時, 你需要複製一個或者多個檔案作為構建過程的一部分。沒有問題, 這是小事一樁。使用mix.copy() 方法指定原始檔或資料夾,然後指定您想要的目標資料夾/檔案

mix.copy('node_modules/vendor/acme.txt', 'public/js/acme.txt');

在編譯時,'acme' 檔案將被複制到 'public/js/acme.txt'。這是一個常見的用例,當你希望將一組字型通過 NPM 安裝到 public 目錄時。

系統通知

預設情況下,Laravel Mix將顯示每個編譯的系統通知。這樣,你就可以快速檢視是否有需要查詢的錯誤。但是,在某些情況下,這是不可取的(例如在生產伺服器上編譯)。如果發生這種情況,它們可以從你的 webpack.mix.js 檔案中禁用。

mix.js(src, output)
   .disableNotifications();

檔案組合和最小化

mix.combine(['src', 'files'], 'destination');
mix.babel(['src', 'files'], destination);
mix.minify('src');
mix.minify(['src']);

如果使用得當,Laravel Mix 和 webpack 應該負責所有必要的模組捆綁和最小化。但是,你可能有一些遺留程式碼或第三方庫需要連線和最小化, 這並不是一個問題。

組合檔案

考慮下面的程式碼片段:

mix.combine(['one.js', 'two.js'], 'merged.js');

這自然會合並 one.jstwo.js 到一個單獨的檔案,叫做 merged.js。與往常一樣,在開發期間,合併檔案將保持未壓縮狀態。但是,對於生產(export NODE_ENV=production),這個命令將會最小化 merged.js

組合檔案與Babel編譯。

如果需要組合 使用 ES2015 方法編寫的JavaScript檔案,你可以更新的 mix.combine() 呼叫 mix.babel()。方法簽名相同。唯一的區別是,在將檔案組合起來之後,Laravel Mix將對結果進行Babel編譯,從而將程式碼轉換成所有瀏覽器都能理解的JavaScript程式碼。

mix.babel(['one.js', 'two.js'], 'merged.js');

最小化檔案

同樣,你也可以使用 mix.minify() 命令縮小一個或多個檔案。

mix.minify('path/to/file.js');
mix.minify(['this/one.js', 'and/this/one.js']);

這裡有一些值得注意的事情:

  • 該方法將建立一個額外的 *.min.ext 檔案。因此,壓縮 app.js 將生成 app.min.js
  • 再一次宣告,壓縮只會在生產過程中發生。(export NODE_ENV=production)。
  • 不需要呼叫 mix.combine(['one.js', 'two.js'], 'merged.js').minify('merged.js'); ,只使用單一的 mix.combine() 呼叫。它會兼顧兩者。

    重要:請注意,壓縮只適用於CSS和JavaScript檔案。minifier不理解任何其他提供的檔案型別。

自動載入

mix.autoload({
   jquery: ['$', 'window.jQuery']
});

Webpack提供了必要的功能,可以在 Webpack 所要求的每個模組中把一個模組作為變數。如果你使用的是一個特定的外掛或庫,它依賴於一個全域性變數,例如jQuery, mix.autoload() 可能會對你有用。

考慮下面的例子:

mix.autoload({
   jquery: ['$', 'window.jQuery']
});

該程式碼片段指定 webpack 應該將 var $ = require('jquery') 新增到它所遇到的全域性$識別符號或 window.jQuery 中。漂亮!

事件鉤子

mix.then(function () {});

你可能需要監聽每次 webpack 完成編譯的事件。也許你需要手動應用一些適合你的應用程式的邏輯。如果是這樣,您可以使用 mix.then() 方法來註冊任何回撥函式。這裡有一個例子:

mix.js('resources/assets/js/app.js', 'public/js')
   .then(() => {
        console.log('webpack has finished building!');
   });

回撥函式將通過 webpack Stats 物件,允許對所執行的編譯進行檢查:

mix.js('resources/assets/js/app.js', 'public/js')
   .then((stats) => {
        // array of all asset paths output by webpack
        console.log(Object.keys(stats.compilation.assets));
   });

可以在這裡找到Stats物件的官方文件 : https://github.com/webpack/docs/wiki/node.js-api#stats

快速 webpack 配置

mix.webpackConfig({} || cb);

當然,你可以自由編輯提供的 webpack.config.js 檔案,在某些設定中,更容易直接從你的 webpack.mix.js 修改或覆蓋預設設定。對於Laravel應用來說尤其如此,預設情況下是在專案根資料夾中沒有 webpack.config.js

例如,你可能希望新增一個由webpack自動載入的模組的自定義陣列。在這個場景中,您有兩個選項:

  • 根據需要編輯你的 webpack.config.js 檔案
  • 在你的 webpack.mix.js 中呼叫 mix.webpackConfig() 檔案,並傳遞重寫引數。然後混合將進行一個深度合併。
    下面,作為一個示例,我們將為 Laravel Spark 新增一個自定義模組路徑。
mix.webpackConfig({
    resolve: {
        modules: [
            'node_modules',
            path.resolve(__dirname, 'vendor/laravel/spark/resources/assets/js')
        ]
    }
});

使用回撥函式

當傳遞迴調函式時,你可以訪問webpack及其所有屬性。

mix.webpackConfig(webpack => {
    return {
        plugins: [
            new webpack.ProvidePlugin({
                $: 'jquery',
                jQuery: 'jquery', 
                'window.jQuery': 'jquery',
            })
        ]
    };
});

擴充套件 Mix

基於元件的系統 Mix 使用場景構建它的API,你也可以訪問—是否為你的專案擴充套件Mix,或者作為一個可重用的包分發到世界。

例子

// webpack.mix.js;
let mix = require('laravel-mix');

mix.extend('foo', function(webpackConfig, ...args) {
    console.log(webpackConfig); // the compiled webpack configuration object.
    console.log(args); // the values passed to mix.foo(); - ['some-value']
});

mix.js('src', 'output').foo('some-value');

在上面的示例中,我們可以看到 mix.extend() 接受兩個引數:在定義元件時應該使用的名稱,以及一個回撥函式或類,這些函式註冊並組織必要的webpack邏輯。在後臺,一旦構建了底層webpack配置物件,Mix將觸發這個回撥函式。這將給你一個機會來插入或覆蓋任何必要的設定。

雖然簡單的回撥函式可能對快速擴充套件很有用,但在大多數情況下,您可能希望構建一個完整的元件類,比如:

mix.extend(
    'foo',
    new class {
        register(val) {
            console.log('mix.foo() was called with ' + val);
        }

        dependencies() {}

        webpackRules() {}

        webpackPlugins() {}

        // ...
    }()
);

在擴充套件 Mix 時,通常需要觸發一些指令:

  • 安裝這些依賴關係。
  • 將此規則/載入程式新增到 webpack 中。
  • 包含這個webpack外掛。
  • 完全覆蓋webpack配置的這一部分。
  • 將此配置新增到Babel。
  • 等。

這些操作中的任何一個都是帶有 Mix 元件系統有聯絡。

元件的介面

  • name:當呼叫元件時,應該使用什麼作為方法名。(預設為類名。)
  • dependencies:列出應該由Mix安裝的所有npm依賴項。
  • register:當您的元件被呼叫時,所有的使用者引數將立即被傳遞給這個方法。
  • boot:啟動元件。這個方法是在使用者的webpack.mix之後觸發的。js檔案已經載入完畢。
  • webpackEntry:附加到主混合webpack入口物件。
  • webpackRules:與主webpack載入器合併的規則。
  • webpackplugin:與主webpack配置合併的外掛。
  • webpackConfig:覆蓋生成的webpack配置。
  • babelConfig:額外的Babel配置應該與Mix的預設值合併。

這裡有一個示例/虛擬元件,它可以讓你更好地瞭解如何構建自己的元件。更多的例子,請參考在後臺Mix 使用的元件

class Example {
    /**
     * The optional name to be used when called by Mix.
     * Defaults to the class name, lowercased.
     *
     * Ex: mix.example();
     *
     * @return {String|Array}
     */
    name() {
        // Example:
        // return 'example';
        // return ['example', 'alias'];
    }

    /**
     * All dependencies that should be installed by Mix.
     *
     * @return {Array}
     */
    dependencies() {
        // Example:
        // return ['typeScript', 'ts'];
    }

    /**
     * Register the component.
     *
     * When your component is called, all user parameters
     * will be passed to this method.
     *
     * Ex: register(src, output) {}
     * Ex: mix.yourPlugin('src/path', 'output/path');
     *
     * @param  {*} ...params
     * @return {void}
     *
     */
    register() {
        // Example:
        // this.config = { proxy: arg };
    }

    /**
     * Boot the component. This method is triggered after the
     * user's webpack.mix.js file has executed.
     */
    boot() {
        // Example:
        // if (Config.options.foo) {}
    }

    /**
     * Append to the master Mix webpack entry object.
     *
     * @param  {Entry} entry
     * @return {void}
     */
    webpackEntry(entry) {
        // Example:
        // entry.add('foo', 'bar');
    }

    /**
     * Rules to be merged with the master webpack loaders.
     *
     * @return {Array|Object}
     */
    webpackRules() {
        // Example:
        // return {
        //     test: /\.less$/,
        //     loaders: ['...']
        // });
    }

    /*
     * Plugins to be merged with the master webpack config.
     *
     * @return {Array|Object}
     */
    webpackPlugins() {
        // Example:
        // return new webpack.ProvidePlugin(this.aliases);
    }

    /**
     * Override the generated webpack configuration.
     *
     * @param  {Object} webpackConfig
     * @return {void}
     */
    webpackConfig(webpackConfig) {
        // Example:
        // webpackConfig.resolve.extensions.push('.ts', '.tsx');
    }

    /**
     * Babel config to be merged with Mix's defaults.
     *
     * @return {Object}
     */
    babelConfig() {
        // Example:
        // return { presets: ['react'] };
}

請注意,上面示例中的每個方法都是可選的。在某些情況下,您的元件可能只需要新增一個webpack載入程式和/或調整混合使用的Babel配置。沒有問題的話省略其餘的介面。

class Example {
    webpackRules() {
        return {
            test: /\.test$/,
            loaders: []
        };
    }
}

現在,當 Mix 構造底層 webpack 配置時,你的規則將包含在生成的webpackConfig.module.rules 陣列中。

使用

一旦你構建或安裝了想要的元件,只需從 webpack.mix.js 中獲取它即可,你都準備好了。

// foo-component.js

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

class Example {
    webpackRules() {
        return {
            test: /\.test$/,
            loaders: []
        };
    }
}

mix.extend('foo', new Example());
// webpack.mix.js

let mix = require('laravel-mix');
require('./foo-component');

mix
    .js('src', 'output')
    .sass('src', 'output')
    .foo();

自定義方法

LiveReload

當Laravel Mix 與 Browsersync 已經支援了開箱即用,你可能更喜歡使用LiveReload, 當檢測到修改時,LiveReload可以自動監視您的檔案並重新整理頁面。

安裝 webpack-livereload-plugin

npm install webpack-livereload-plugin@1 --save-dev

配置 webpack.mix.js

將以下幾行新增到 webpack.mix.js 底部。

var LiveReloadPlugin = require('webpack-livereload-plugin');

mix.webpackConfig({
    plugins: [
        new LiveReloadPlugin()
    ]
});

雖然 LiveReload 有她很好用的預設值,但是這裡可以檢視一個可用的外掛選項列表

安裝 LiveReload.js

最後,我們需要安裝LiveReload.js。您可以通過 LiveReload Chrome 外掛,或者在你的主要站點模板的關閉

相關文章