Laravel 文件閱讀:用 Laravel Mix 編譯資產

zhangbao發表於2017-09-13

翻譯、衍生自: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 協議》,轉載必須註明作者和本文連結

相關文章