本篇是我们系列课程《Laravel5.7优雅实战入门:第二版》《Laravel 5.7&Vue 2.x深度整合实战:第二版》的扩展阅读。

在2019年1月份,laravel mix这个默认的前端资源管理工具,升级到了4.0版本,由于是刚刚升级,可能还存在很多的bug与报错,所以在此统一汇总解决一下。

(一)官方的新版本特性与好处:

  • 更快的编译速度
  • 更快的npm install安装速度
  • 背后依赖的webpack升级到了4
  • vue-loader升级到了15
  • Babel升级到了7
  • 自动的依赖抽离。如果你调用mix.extract()方法,不加任何参数,所有的组件依赖(你从node_modules/引入的任何第三方组件),就都会被自动地抽离出来
  • css的压缩(基于cssnano)选项可以进一步添加了
  • PostCSS的插件,可以在单独的调用中传到mix.sass/less/stylus()中了。这意味着如果需要的话,每次的mix.sass()调用,你都可以往里面添加独特的PostCSS plugins
  • JS的优化和压缩依赖,由原来的Uglify变为Terser
  • SASS的优化和压缩依赖,由原来的node-sass变为Dart Sass。这个变动会稍微增加编译的时间,好处是在npm install的时候,能更快、更稳定
  • 改进了Bebel配置的融合策略。现在可以覆写或更改任何Mix里提供的、默认的Babel插件(plugins)和预设(presets)了,只需要在项目根目录创建一个.babelrc文件即可

(二)如何从之前的版本升级到Mix 4

npm remove laravel-mix
npm install laravel-mix@^4.0.0 --save-dev

升级了以后,如果你遇到跟vue-template-compiler相关的问题,多半是因为vuevue-template-compiler的版本号要一模一样才行,当两个版本不一致时就会报mismatch的错误,所以只需要更新vuevue-template-compiler其中一个的版本号,让它跟另一个一致即可。

(三)注意事项

  • 如果你的项目重度使用了JS的动态引入(dynamic imports),可能你得等到下一年webpack 5发布后再更新。在那之前,这方面会存在一些已知的编译问题,而且无法修复。一旦webpack 5发布了,Mix也会随后更新。如果你还不懂JS的动态引入(dynamic imports),那么很可能这不会影响到你的项目。(传统上我们import后面加上字符来引入组件或其他的js文件,新近的js支持import()作为一个方法来调用组件,这样返回的就是一个Promise,方便做一些组件的延迟加载之类)
  • Sass支持现在是一个按需的组件了。在之前的版本里,Mix默认就带着node-sasssass-loader,不管你的项目是否真的需要sass编译。为了提高组件安装(npm installs)的时间,这两个sass相关的组件,就成了按需安装,也即只有当你使用到了mix.sass()命令,它们才会被自动安装。当你初次运行npm run dev,并且用到了sass()方法时,相应依赖就会被安装,存到dev-dependencies列表里。

(四)初次npm install或yarn install提示webpack-cli相关的错误

如果你是一个全新的项目,在初次执行npm installyarn install的时候,很有可能会出现如下类似的错误:

error ···\mix-test\node_modules\webpack-cli: Command failed.
Exit code: 1
Command: lightercollective
Arguments:
Directory: ···\mix-test\node_modules\webpack-cli
Output:
'lightercollective' is not recognized as an internal or external command,
operable program or batch file.

它会说webpack-cli命令失败,还说什么webpack-cli目录下的'lightercollective'找不到,这个的原因是到了webpack 4的时代,webpack和webpack-cli不再是一个组件了,原来它们是一块的,现在webpack-cli独立出来了,得单独安装一下:

yarn add webpack-cli

或者

npm install webpack-cli

一般这样之后,再执行npm installyarn install,就没问题了。如果安装了还有问题,那么可能你是老的项目或者老的环境,可能webpack的版本还不是4,就跟webpack-cli对应不起来了,期间还会涉及到全局的webpack和webpack-cli,以及本项目的webpack和webpack-cli之间的冲突,这种时候,如果你实在不愿意折腾,就干脆package.json里将laravel-mix的版本号改为3.0.0,然后再安装就得了

(五)ES模块的引入(JS组件的require或import)

由于vue-loader 15的更新,如果你在引入ES模块的时候使用了 CommonJS的格式,也即require()的方式,你就需要在后面追加上.default,例如这样:

Vue.component(
    'example-component', 
-   require('./components/ExampleComponent.vue')
+  require('./components/ExampleComponent.vue').default
);

将原来require()的方式,转换成ES的import ... from '...'的方式,是更推荐的:

import ExampleComponent from './components/ExampleComponent.vue';

Vue.component('example-component', ExampleComponent);

(六.1)由Node Sass 转到 Dart Sass

由Node Sass 转到 Dart Sass,虽然大同小异,但是编译期间你可能会遇到一些变化、或警告信息,你可以一点点地将报错解决掉,也可以自行切换回node-sass:

npm install node-sass
mix.sass('resources/sass/app.sass', 'public/css', {
    implementation: require('node-sass')
});

(六.2)无法找到sass模块的错误

很有可能升级期间你会遇到类似的报错:

/project/node_modules/webpack-cli/bin/cli.js:235
                throw err;
                ^

Error: Cannot find module 'sass'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:603:15)
    at Function.Module._load (internal/modules/cjs/loader.js:529:25)
    at Module.require (internal/modules/cjs/loader.js:657:17)
    at require (/project/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at implementation (/project/node_modules/laravel-mix/src/components/Sass.js:52:39)
    at implementation (/project/node_modules/laravel-mix/src/components/Preprocessor.js:125:61)
    at global.tap (/project/node_modules/laravel-mix/src/helpers.js:10:5)

注意错误提示里的Cannot find module 'sass', 说是无法找到sass模块,然后可能就会有同学不断地执行npm install node-sass,但是这个错误依然无法解决.那么原因呢,是mix背后不再默认依赖node-sass,而是sass了,它们两个并不是一个组件,所以这时候你可以执行:

npm -g i sass

或者

yarn add sass

当然了,你也可以像之前说的,将mix进行配置,让它继续依赖以前的node-sass:

mix.sass('resources/assets/sass/app.scss', 'public/css', {
  implementation: require('node-sass')
});

(七)Vue组件里的sass编译

如果你的项目里没有调用过mix.sass()方法,因为这样的话它就会自动安装sass相关的依赖,但是你只是在vue组件里的style标签上声明了lang="sass",那么你就需要单独安装node-sass 或 sass。 因为Mix无法知道你会在Vue组件里具体用哪个样式处理器,所以你得自行安装相应组件。

比如你可以这样

npm install node-sass sass-loader

或者

npm install sass sass-loader 

同样的道理也适用于less和Stylus

(八)生产环境编译时提示css-loader相关的错误

可能你其他的mix编译都正常,比如npm run devnpm run watch,但是在执行生产环境编译命令npm run prod时,却出现了一大堆的报错,类似这样的:

...
Module build failed (from ./node_modules/css-loader/dist/cjs.js):
ValidationError: CSS Loader Invalid Options

options should NOT have additional properties
...

说css-loader的配置项里不应该有额外的参数,出现这个问题的原因是,新版2.x的css-loader已经删掉了minimize: true这个选项,而mix在执行npm run prod时需要压缩css,默认是带着这个选项的,当然mix背后所依赖的css-loader是1.x版本的,并不是最新版.所以如果你出现上面的报错,说明你的项目在别的地方安装了2.x版本的css-loader,所以就会出错了.那么知道了原理,解决起来也就非常简单了--删掉你项目里的新版css-loader,用mix会自动安装的老版本css-loader,或者你也可以手动降级css-loader到1.x的版本

比如可以这样:

yarn remove css-loader
yarn add css-loader@1.0.1

然后你再执行npm run prod应该就不再有问题了.

当然有可能有同学好奇,那么css-loader新版本里删掉了minimize: true这个选项,以后该用啥来压缩生产环境的css呢?那么现在一致推荐的是optimize-css-assets-webpack-plugin这个组件,当然奇怪的是mix 4已经用到了这个新的压缩组件,但却同时保留了旧的css-loader的版本和配置,这应该是个还没catch到的bug

(九)完全删掉了 fastSass() 和 standaloneSass() 两个方法

fastSass() 和 standaloneSass() 两个方法被完全移除了,后者只是前者的一个别名的方法而已。

为了提高只是需要编译css这部分人的性能需求,fastSass() 和 standaloneSass() 这两个方法可以将sass编译跟webpack的基本编译分离开来,但是呢,似乎对新手来说,这更容易让人困惑。升级后,你得将之前的mix.fastSass()改成mix.sass()

- mix.fastSass()
- mix.standaloneSass()
+ mix.sass()

(十)删掉了调用Mix时的.mix后缀属性

删掉了已被弃用的.mix属性,如果你的webpack.mix.js文件里有require('laravel-mix').mix,得改成require('laravel-mix')

- require('laravel-mix').mix
+ require('laravel-mix')

(十一)Babel 7的支持

Babel官方的插件命名空间有所改变,都统一改成了@babel名下。你需要更新package.json文件,将其中所有babel-plugin-[name]相关的如下更改:

- "babel-plugin-[name]": "6.x"
+ "@babel/plugin-[name]": "7.x"

如果你之前创建过.babelrc文件,那么在其中也相应更改:

- "plugins": ["babel-plugin-transform-object-rest-spread"]
+ "plugins": ["@babel/plugin-proposal-object-rest-spread"]

(十二)从Uglify 转到 Terser

如果你项目里有更改过之前Uglify的一些配置,比如通过Config.uglify = {},你就得改成Config.terser = {},具体的配置大部分都是一样的。

Terser配置API

webpack.mix.js:

mix.options({
-    uglify: {
-        uglifyOptions: {
+    terser: {
+        terserOptions: {
           warnings: true
        }
    }
});

(十三)解决npm组件安装问题的终极大法

如果升级mix期间,你还是遭遇一些莫名其妙的报错,基于网上的各种解决方案,你觉得自己明明都做对了,但还是报错,那么这个时候,可能是一些缓存\历史遗留在作怪,你可以基于下面的流程来尝试

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

最后一步也可以是yarn install