在 Laravel 项目中使用 webpack-encore的方法


Posted in PHP onJuly 21, 2019

看过我之前写过的博客的应该知道我一直是 laravel-mix 的死忠粉,有好几篇文章都是关于它的。每每提到 laravel-mix 时更是不吝溢美之词。然而就在大概一个月前,我却决定不再使用它,而转投 webpack-encore 阵营。

至于为什么放弃 laravel-mix,主要是因为它的维护状况堪忧,不仅更新节奏缓慢,许多 Issue 久悬未决,更重要的是,作者似乎将很多 bug 完全寄希望于 webpack5,哪怕有热心人士 PR 了,也通常被关掉,然后回复说“兄 dei,这个坑等 webpack5 出来就好了,我之前试过没弄好,估计你这也填好坑,干脆安分点儿等 webpack5 吧”(不是原话,但差不多是这意思)。但最终让我下定决心寻求替代方案的,则是这个 Issue ,细翻源码,发现相关功能依赖的还是 extract-text-webpack-plugin,而这个包,早在 webpack4 发布不久就被宣布废弃了(现在去看它的官方仓库已经被设置为 archived),而作者似乎完全没有使用 mini-css-extract-plugin 的意思。

正所谓爱之深,责之切,在对 laravel-mix 表示失望之后,我翻出了自己 star 多时的另一包 webpack-encore,虽说很早就 star 了,但之前却没试用过它,可能也是因为对于 laravel-mix 的偏爱,然而这次,不试便罢,试完之后大有相见恨晚之意。

webpack-encore 是 Symfony 官方的前端集成构建工具,同样是基于 webpack,但它的 API 设计得更为友好,而且文档更完善,当然更关键的一点是,坑更少啊……从开始读它的文档,倒把手里一个项目从 laravel-mix 迁移到 webpack-encore,只用了几个小时,并且期间相当顺利。而我迁移的这个项目,是一个 Laravel 项目,所以下面就分享下,如果在 Laravel 项目中使用 webpack-encore 替代 laravel-mix

安装依赖

首先当然是安装依赖

yarn add -D @symfony/webpack-encore

需要注意的是,webpack-encore 没有像 laravel-mix 那样在自己内部依赖 vue-tempplate-compiler 之类的包,所以如果自己项目里用动了这些,需要自己在项目里手动安装好。

配置 webpack

在项目根目录下新建一个 webpack.config.js 文件并在其中配置 webpack-encore 功能(实际上它最终也是一个标准的 webpack 配置文件),以最基本的玩法为例。

const Encore = require('@symfony/webpack-encore')

Encore
// directory where compiled assets will be stored
 .setOutputPath('public/js/')
 // public path used by the web server to access the output path
 .setPublicPath('/js')
 // only needed for CDN's or sub-directory deploy
 //.setManifestKeyPrefix('build/')

 /*
  * ENTRY CONFIG
  *
  * Add 1 entry for each "page" of your app
  * (including one that's included on every page - e.g. "app")
  *
  * Each entry will result in one JavaScript file (e.g. app.js)
  * and one CSS file (e.g. app.css) if you JavaScript imports CSS.
  */.addEntry('app', './resources/js/app.js')

// will require an extra script tag for runtime.js
// but, you probably want this, unless you're building a single-page app
 .enableSingleRuntimeChunk()

 .cleanupOutputBeforeBuild().enableSourceMaps(!Encore.isProduction())
// enables hashed filenames (e.g. app.abc123.css)
 .enableVersioning(Encore.isProduction())

 .enableVueLoader()
 .enableSassLoader(options => {
  options.implementation = require('sass')
 })

// fetch the config, then modify it!
const config = Encore.getWebpackConfig()

// export the final config
module.exports = config

新增 php helper 函数

Laravel 自带了一个 mix() 函数用于引用 mix 编译的资源,与之类似,syfony 也有这样的函数,而且更为方便。为此你需要在 Laravel 项目中自行实现这两方法,下面是我参考 symfony 里相关源码改写的,可能逻辑上并不算完善,但以自己一个多月的使用情况来看,它们表现良好。

use Illuminate\Support\HtmlString;

/**
 * @param string $entryName
 * @return HtmlString
 */
function encore_entry_link_tags(string $entryName): HtmlString
{
  $entryPointsFile = public_path('js/entrypoints.json');

  $jsonResult = json_decode(file_get_contents($entryPointsFile), true);

  if (!array_key_exists('css', $jsonResult['entrypoints'][$entryName])) {
    return null;
  }

  $tags = array_map(function ($item) {
    return '<link rel="stylesheet" href="'.$item.'" rel="external nofollow" />';
  }, $jsonResult['entrypoints'][$entryName]['css']);

  return new HtmlString(implode('', $tags));
}

/**
 * @param string $entryName
 * @return HtmlString
 */
function encore_entry_script_tags(string $entryName): HtmlString
{
  $entryPointsFile = public_path('js/entrypoints.json');

  $jsonResult = json_decode(file_get_contents($entryPointsFile), true);

  if (!array_key_exists('js', $jsonResult['entrypoints'][$entryName])) {
    return null;
  }

  $tags = array_map(function ($item) {
    return '<script src="'.$item.'"></script>';
  }, $jsonResult['entrypoints'][$entryName]['js']);

  return new HtmlString(implode('', $tags));
}

使用 encore_entry_link_tags 和 encore_entry_script_tags 引用编译的前端资源

在模板里使用前面添加的 helper 函数引用资源,你会发现它比 Laravel 自带的 mix() 函数更方便,只需要一个函数,就可以自动引入 vendor.js 和 app.js 了。

<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- CSRF Token -->
  <meta name="csrf-token" content="{{ csrf_token() }}">

  <title>{{ config('app.name') }}</title>

  <!-- app.css -->
  {{ encore_entry_link_tags('app') }}
</head>
<body>

  <div id="app"></div>

  {{ encore_entry_script_tags('app') }}
</body>
</html>

修改 package.json 中的脚本(scripts)

因为 laravel 项目默认 package.json 中 develop 等相关的脚本都是使用 laravel-mix 的,为了方便日常开发,现在要对它们进行一些调整,改用 webpack-cocore。调整后大致如下,你也可以根据自己实际应用情况进行其它调整

"scripts": {
  "dev": "npm run development",
  "development": "cross-env NODE_ENV=development encore dev",
  "watch": "npm run development -- --watch",
  "watch-poll": "npm run watch -- --watch-poll",
  "hot": "encore dev-server --port=9001 --hot",
  "prod": "npm run production",
  "production": "cross-env NODE_ENV=production encore production"
},

运行脚本,愉快撸 BUG

做完前面的这些步骤之后,在终端执行 yarn run hot ,浏览器中输入项目绑定的域名(如 app.test),就可以体验方便高效的 HMR 开发了。

后记

使用 webpack-encore 已经快两个月了,这期间总体说来相当顺利,小坑虽然有,但没什么大坑。去 github 上提 issue,维护成员基本上都很友善耐心,几个小时就会有回复。这种态度也让我对它更加放心了,相信它会折腾得越来越好。虽然 webpack-encore 是作为 Symfony 默认集成工具来设计的,但这并不妨碍它在 Laravel 中发挥强大威力。

相比于 laravel-mi,encore 的 API 以及一些默认配置方面考虑得更为科学和全面,想要配置 vue-loader 或者 ts-loader 之类的,只需要调用相应的方法。另外还有点让我先惊讶的是,他们竟然对 watchOptions.ignored 的默认值也考虑到了,默认忽略 /node_modules/,降低 CPU 占用。当然,更为重要的是,mix4 里因为一些 bug 而无法使用的功能,在 encore 里却正常,如 dynamic import。

总之,如果你已经发现了 laravel-mix 的种种不足但又苦于没更好选择的话,不妨试试 webpack-encore,相信你会对它爱不释手。

总结

以上所述是小编给大家介绍的在 Laravel 项目中使用 webpack-encore的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧!

PHP 相关文章推荐
Zend的AutoLoad机制介绍
Sep 27 PHP
PHP获取搜索引擎关键字来源的函数(支持百度和谷歌等搜索引擎)
Oct 03 PHP
解析PHP中$_FILES的使用以及注意事项
Jul 05 PHP
php导出CSV抽象类实例
Sep 24 PHP
php中heredoc与nowdoc介绍
Dec 25 PHP
PHP获取当前相对于域名目录的方法
Jun 26 PHP
各种快递查询--Api接口
Apr 26 PHP
浅谈htmlentities 、htmlspecialchars、addslashes的使用方法
Dec 09 PHP
PHP中Cookie的使用详解(简单易懂)
Apr 28 PHP
PHP中PDO事务处理操作示例
May 02 PHP
PHP实现的AES加密、解密封装类与用法示例
Aug 02 PHP
PHP如何开启Opcache功能提升程序处理效率
Apr 27 PHP
Smarty缓存机制实例详解【三种缓存方式】
Jul 20 #PHP
PHP INT类型在内存中占字节详解
Jul 20 #PHP
PHP检测一个数组有没有定义的方法步骤
Jul 20 #PHP
PHP defined()函数的使用图文详解
Jul 20 #PHP
php实现 master-worker 守护多进程模式的实例代码
Jul 20 #PHP
PHP抽象类和接口用法实例详解
Jul 20 #PHP
PHP使用PDO、mysqli扩展实现与数据库交互操作详解
Jul 20 #PHP
You might like
Windows下的PHP 5.3.x安装 Zend Guard Loader教程
2014/09/06 PHP
php中html_entity_decode实现HTML实体转义
2018/06/13 PHP
js bind 函数 使用闭包保存执行上下文
2011/12/26 Javascript
Ext中下拉列表ComboBox组件store数据格式用法介绍
2013/07/15 Javascript
JavaScript及jquey实现多个数组的合并操作
2014/09/06 Javascript
node.js中的fs.statSync方法使用说明
2014/12/16 Javascript
检测一个函数是否是JavaScript原生函数的小技巧
2015/03/13 Javascript
jQuery实现选项联动轮播效果【附实例】
2016/04/19 Javascript
浅析JS异步加载进度条
2016/05/05 Javascript
详解JSON1:使用TSQL查询数据和更新JSON数据
2016/11/21 Javascript
使用jQuery实现简单的tab框实例
2017/08/22 jQuery
Bootstrap popover 实现鼠标移入移除显示隐藏功能方法
2018/01/24 Javascript
element-ui中select组件绑定值改变,触发change事件方法
2018/08/24 Javascript
ant design 日期格式化的实现
2020/10/27 Javascript
解决vue-cli输入命令vue ui没效果的问题
2020/11/17 Javascript
Python实现的下载8000首儿歌的代码分享
2014/11/21 Python
python实现发送和获取手机短信验证码
2016/01/15 Python
理解Python中的With语句
2016/03/18 Python
Python面向对象之静态属性、类方法与静态方法分析
2018/08/24 Python
python 定时器,实现每天凌晨3点执行的方法
2019/02/20 Python
python django生成迁移文件的实例
2019/08/31 Python
使用pyqt 实现重复打开多个相同界面
2019/12/13 Python
Django windows使用Apache实现部署流程解析
2020/10/12 Python
python中altair可视化库实例用法
2021/01/26 Python
Nike香港官网:Nike HK
2019/03/23 全球购物
求职简历自荐信
2013/10/20 职场文书
幼儿园安全责任书
2014/04/14 职场文书
2014国庆节商场促销活动策划方案
2014/09/16 职场文书
基层领导干部“四风”问题批评与自我批评
2014/09/23 职场文书
医院保洁员岗位职责
2015/02/13 职场文书
python关于集合的知识案例详解
2021/05/30 Python
详解Python常用的魔法方法
2021/06/03 Python
浅谈Python从全局与局部变量到装饰器的相关知识
2021/06/21 Python
Java 中的 Unsafe 魔法类的作用大全
2021/06/26 Java/Android
详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类
2022/04/08 Java/Android
Mysql将字符串按照指定字符分割的正确方法
2022/05/30 MySQL