对于想在 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即可。