Laravel Mix? Laravel 的前端資源編譯器

JokerLinly發表於2017-03-20

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.

相關文章