對于想在 Laravel 項目中提取 Vue 組件中的 CSS 樣式到一個文件中,laravel-mix 的文檔寫得很簡單,只需要添加一行配置項即可:
mix.options({
extractVueStyles: true
});
然而在實際開發中,我還是遇到了問題。
如果你的Vue組件是全局注冊并且是同步加載的:
Vue.component('example', require('./components/Example.vue'));
那么配置好 extractVueStyles: true
就基本可以了。只不過如果你在某一個組件的 <script>
標簽中通過 import
的方式引入了CSS樣式,那么這部分樣式最終還是會注入到 html 頁面的 <style>
標簽中。
比如我項目中用到了一個社交分享組件,最終 client.css
里面的內容還是無法單獨提取出來:
import Share from "vue-social-share";
import "vue-social-share/dist/client.css";
export default {
components: {
Share
},
data() {
return {
shareConfig: {
sites: ["qq", "qzone", "weibo"]
}
};
}
};
這只是遇到的第一個問題。其次,由于為了減少白屏時間,我在項目中使用了異步組件的加載方式,這下子上面的方法幾乎就行不通了。
Vue.component('example', () => import('./components/Example.vue'));
這里多說一句,使用異步組件必須安裝 babel-plugin-syntax-dynamic-import
插件,然后在項目根路徑下新建一個 .babelrc
文件添加配置:
{
"plugins": ["syntax-dynamic-import"]
}
其實,這兩個CSS提取不完整的問題的根本原理是一致的,最終我還是在 vue-cli 的源碼中找到了 ExtractTextPlugin 插件,看一下 allChunks
的定義就很容易明白了:
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash:8].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true,
}),
原來是 laravel-mix 設計本身的問題,沒有配置這個 allChunks
,所以必須需要通過修改源碼的方式來修復。
找到 node_modules\laravel-mix\src\components\Vue.js
文件中的 extractPlugin 方法,傳遞一個對象給構造函數,并加上一條 allChunks: true
直接搞定!
extractPlugin() {
if (typeof Config.extractVueStyles === 'string') {
// return new ExtractTextPlugin(this.extractFilePath());
return new ExtractTextPlugin({
filename: this.extractFilePath(),
allChunks: true,
});
}
// ...
注:一般選擇在生產環境下提取CSS即可。