hostnet / webpack-bundle
整合 Webpack 和 Symfony
Requires
- php: ^7.1.0
- ext-json: *
- monolog/monolog: ~1.25
- symfony/monolog-bundle: ^4.0.0||^3.1.0
- symfony/symfony: ^4.3.9||^3.4.36
- twig/twig: ^2.7.2
Requires (Dev)
- hostnet/phpcs-tool: ^8.3.3
- phpunit/phpunit: ^7.5.9
- symfony/phpunit-bridge: ^3.3.2
Conflicts
- phpdocumentor/type-resolver: <0.2.1
README
弃用
此包已被弃用。请使用替代工具,如
hostnet/webpack-bundle
简介
本包假设您已经具备一些关于webpack的基本知识;它是什么以及它为您做了什么。如果不是这样,请先阅读此内容。这只需要一分钟,但值得。
本包不是将所有与包相关的资产放在一个位置,而是处理来自两个不同位置的资产。做出这个决定的原因是因为webpack的资产是在服务器上编译的,不应从浏览器访问。
Resources/assets
包含由webpack编译的文件。Resources/public
包含符号链接或复制到/<dump_path>/<lowercased_bundle_name>/
的资产
当在 调试模式 下运行时,这两个目录都会被监视。当资产被添加、修改或删除时,编译源将直接更新。
本包包含两个 twig 函数
webpack_asset(url)
: 解析编译后的资产文件。例如:webpack_asset('@AppBundle/app.js')
解析为 AppBundle 中的Resources/assets/app.js
。webpack_public(url)
: 解析从Resources/public
目录中导出的公共资产。包引用的方式与webpack_asset
相同。
请注意,webpack_asset
返回一个包含两个键的数组:js
和 css
。更多关于此的信息可以在 快速入门 示例中找到。
安装
使用 composer 进行安装。
"require" : { "hostnet/webpack-bundle" : "1.*" }
安装后,在 AppKernel
类中启用包 Hostnet\Bundle\WebpackBundle\WebpackBundle
。
警告:为了使webpack twig标签能够检测编译文件,webpack必须已经编译。因此,在缓存预热之前必须运行编译命令
webpack:compile
。
升级到 2.0
由于Twig的一些破坏性更改,webpack-bundle 2.0 已发布以与新的twig版本兼容。
为了确保平稳升级,请确保您的项目中具有以下内容
- PHP 7.1 或更高版本
- Symfony 3.3.0 或更高版本
- Twig 2.4.0 或更高版本
本版本没有进行配置更改。如果您的项目使用上述版本,则在升级webpack-bundle到2.0时不应遇到任何问题。
以下版本中进行了以下额外更改:
- 使用PHP 7严格类型声明
- 使用命名空间化的Twig类,这些类是在Twig 2.4中引入的,以支持未来兼容性(例如使用
\Twig\Environemnt
而不是\Twig_Environment
) - 使用
phpcs
强制执行代码风格,并强制执行Hostnet指定的额外规则集 - 由于我们的代码风格规则强制执行,将类
CSSLoader
重命名为CssLoader
- 现在,用于内联javascript/css源文件的生成文件名来自
TokenStream->getSourceContext()->getName()
而不是TokenStream->getFilename()
。后者函数已被从Twig中删除 - 创建FCQN服务并添加别名以确保向后兼容
- 使捆绑包与Symfony (3.)4兼容
快速入门
警告:默认情况下,该包假定
node
和webpack
以及任何其他模块已预安装在您的系统上。如果情况不是这样,您需要在启用捆绑包后,在您的config.yml
文件中指定一些配置。有关更多详细信息,请参阅节点配置。
想象一下,在您的应用程序中有以下文件
src/AppBundle/Resources/assets/app.js
src/AppBundle/Resources/assets/image.js
src/AppBundle/Resources/public/images/logo.png
src/AppBundle/Resources/views/base.html.twig
让我们从twig模板开始。
{# src/AppBundle/Resources/views/base.html.twig #} The quick variant: <script src="{{ webpack_asset('@AppBundle/app.js').js }}"></script> The more maintainable variant: Store the result to a variable for easy access. {% set asset = webpack_asset('@AppBundle/app.js') %} <script src="{{ asset.js }}"></script> {% if asset.css is not empty %} <link rel="stylesheet" href="{{ asset.css }}"> {% endif %}
在模板中使用twig函数webpack_asset(url)
指定一个入口点。简而言之,入口点是一个将被编译并导出到输出路径的资产。此路径默认为%kernel.root_dir%/../web
。默认情况下,编译后的文件将命名为app_bundle.app.js
。这两个设置都是可配置的。
webpack_asset
返回一个包含两个键的数组:js
引用编译后的javascript文件,css
引用编译后的css文件。请注意,如果此文件不存在,则css
元素可能为空。后者会在引用的javascript文件(或其依赖项)不包含任何CSS类型文件时发生。
// src/AppBundle/Resources/assets/app.js var image = require('@AppBundle/image.js'); document.write(image('/bundles/app/images/logo.png'));
任何webpack资产都可以使用webpack提供的require
或define
函数。Webpack允许以CommonJS和AMD样式加载文件。如您所注意到的,上面的示例通过简写名称@AppBundle
引用了一个捆绑包。捆绑包会自动为您代理跟踪捆绑包,因此您可以在整个应用程序中自由使用此方法来引用依赖项。
位于Resources/public
目录中的logo.png
文件将自动软链接或复制到/<dump_path>/<lowercased_bundle_name>
。您应将任何不需要处理的文件放置在公共目录中,以避免在调试模式(app_dev)中产生不必要的加载时间。
这是一个简单的图像模块,它返回一个图像HTML标签字符串。
// src/AppBundle/Resources/assets/image.js module.exports = function (src) { return '<img src="' + src + '">'; };
Twig标签
除了webpack_asset
twig函数外,您还可以使用webpack
标签以更优雅的方式指定一个或多个入口点。此标签的语法如下
{% webpack <type: css|js> <list-of-javascript-files> %} {{ asset }} {% endwebpack %}
或者,如果您想包含内联代码而不包含文件
{% webpack <type: inline> [file-type] %} <javascript, css, less, scss, ... code> {% endwebpack %}
如果您想包含javascript文件,只需这样做
{% webpack js '@AppBundle/file1.js' '@AppBundle/file2.js' %} <script src="{{ asset }}"></script> {% endwebpack %}
或者内联版本
{% webpack inline %} <script type="text/javascript"> console.log("Hello world!"); </script> {% endwebpack %}
相同的方法也可以应用于CSS文件。
{% webpack css '@AppBundle/file1.js' %} <link rel="stylesheet" href="{{ asset }}"> {% endwebpack %}
请注意,在CSS示例中,我们仍在引用JavaScript文件。这并不是一个错误。 Webpack从JavaScript文件中提取引用的CSS文件,并将它们放置在单独的CSS文件中 - 如果配置了这样做的话。如果您想包含一个已存在的CSS文件,只需使用常规方法即可。有关CSS文件导出的更多信息,请参阅CSS加载器配置。
警告:由于分割点检测的特性,表达式不会被解析!只接受字符串类型。原因,如之前所述,是性能。所有Twing模板在调试模式下按请求进行标记化。仅标记化它们就比实际解析每一个都要快得多。
关于内联变体的更多信息
如上例所示,您可以可选地指定与inline
类型一起的文件类型。这可以是任何类型的文件扩展名,只需确保您已启用相应的加载器。
例如,js
默认情况下始终有效。但是,如果启用了css-loader
,则css
才有效。如果您已启用了less-loader
或sass-loader
,您可以这样做:
Less版本
<section> {% webpack inline less %} <style> @color: #f00; @size: 42px; body { color: @color; section : { size: @size; } } </style> {% endwebpack %} </section>
Sass版本
<section> {% webpack inline sass %} <style> $color: #f00; $size: 42px; body { color: $color; section : { size: $size; } } </style> {% endwebpack %} </section>
编译器会自动去除<style>
和/或<script>
标签,并将块的正文保存到文件中。然后,该文件将通过使用指向编译文件的link
标签或script
标签来包含到模板中。
配置
此包的配置选项相当多,但所有设置都是可选的,并带有合理的默认值。
以下配置选项直接从webpack本身复制,并可以按照这种方式进行配置。需要注意的是,键是用下划线而不是驼峰命名法编写的。
例如,在webpack中配置output.publicPath
设置将写作
webpack: output: public_path: '/public'
以下"webpack"部分可以通过config.yml
进行配置
output
: http://webpack.github.io/docs/configuration.html#outputresolve
: http://webpack.github.io/docs/configuration.html#resolveresolve_loader
: http://webpack.github.io/docs/configuration.html#resolveloader
选项entry
、resolve.root
、resolve.alias
和resolveModule.modulesDirectories
将根据分割点(入口点)、跟踪的包和指定的(或检测到的)node_modules目录自动配置。如果您指定了这些选项中的任何一个,其值将被附加到生成的值。
Node
为了使此包正常工作,它需要知道nodejs的安装位置以及在哪里可以找到其node_modules目录。如果node在您的服务器上全局安装,则可以省略此设置。
# config.yml webpack: node: binary: '/path/to/node-binary' node_modules_path: '/path/to/node_modules'
多平台配置
由于您的应用程序可能同时运行在windows、linux和mac上,您可能需要指定不同的node二进制文件。如果是这种情况,您可以将一个字符串引用node二进制文件传递给node.binary
选项,而不是传递一个数组。
webpack: node: binary: win32: 'C:\\path\\to\\node32.exe' win64: 'C:\\path\\to\\node64.exe' linux_x32: '/usr/bin/node32' linux_x64: '/usr/bin/node64' darwin: '/path/to/node' fallback: '/if/os/detection/fails/path/to/node'
再次强调,所有设置都是可选的。如果没有指定键,则默认为"node"。这仅当node全局安装时才有效。
包配置
默认情况下,所有启用的包都会被跟踪。但是,出于性能或安全原因,您也可以明确指定一组要跟踪的包。
webpack: bundles: ['AppBundle', 'YourBundle']
将应用程序资源添加到跟踪资产中
如果您决定将资源添加到app/Resources/assets,您只需要添加一个别名,然后就可以通过webpack加载机制进行加载。
webpack: resolve: alias: app: %kernel.root_dir%/Resources/assets
# can be loaded via require('app/base.js');
共享依赖
如果指定了选项output.common_id
,共享依赖将被写入一个独立的javascript或css文件。
例如,以下配置将输出一个shared.js
和一个shared.css
文件。
webpack: output: common_id: 'shared'
在您的模板中,您可以通过webpack_common_js()
和webpack_common_css()
获取到您的公共javascript文件的路径。
<script src="{{ webpack_common_js() }}"></script> <link rel="stylesheet" href="{{ webpack_common_css() }}"> {# will give the following output based on output.common_id #} <script src="/compiled/shared.js"></script> <link rel="stylesheet" href="/compiled/shared.css">
资产输出目录
- 从"public"目录中导出的资产将链接或复制到
<output.dump_dir>
目录。 - 从"assets"目录编译的资产将被写入到
<output.path>
目录。 - twig函数
webpack_asset
返回以<output.public_path>
目录为前缀的编译文件名。
webpack: output: path: '%kernel.root_dir%/../web/compiled/' dump_path: '%kernel.root_dir%/../web/bundles/' public_path: '/compiled/'
path
值代表从客户端视角的资产路径。因此,它必须指定您的app(_dev).php的路径,例如,somedomain.com/my-web/app.php将使其变为%kernel.root_dir%/../web/my-app/compiled/
,如上例所示。
如果output.path
的值是%kernel.root_dir/../web/packed/
,则必须将output.public_path
的值设置为/packed/
。
理想配置
以下配置要求您的node_modules
目录中存在以下模块。
- extract-text-webpack-plugin
- style-loader
- css-loader
- less-loader
- sass-loader
- url-loader
- babel-loader
- ts-loader
由于我们正在创建javascript文件的共享块,您需要手动在基本模板中包含'/compiled/shared.js
'。对于CSS文件也是如此,具体取决于您包含的内容以及包含的位置。
config.yml
webpack: node: binary: '/path/to/node' node_modules_path: '%kernel.root_dir%/../node_modules' output: path: '%kernel.root_dir%/../web/compiled/' dump_path: '%kernel.root_dir%/../web/bundles/' public_path: '/compiled/' common_id: 'shared' loaders: css: all_chunks: true filename: '[name].css' less: all_chunks: true filename: '[name].css' sass: all_chunks: true filename: '[name].css' url: ~ babel: ~ typescript: ~
base.html.twig
<head> <script src="/compiled/shared.js"></script> </head>
在您的twig模板的某个地方
{% webpack js "@YourBundle/SomeModule.js" %} <script src="{{ asset }}"></script> {% endwebpack %} {% webpack css "@YourBundle/SomeModule.js" %} <link rel="stylesheet" href="{{ asset }}"> {% endwebpack %}
编译超时
默认情况下,webpack只有60秒的时间来执行。在webpack需要更多时间的情况下,您可以更新compile_timeout
选项。
webpack: compile_timeout: 60
加载器
加载器允许您require
除javascript以外的文件。本包包含7个默认加载器。
CssLoader
: 包含CSS文件UrlLoader
: 包含图片(转换为base64)LessLoader
: 包含less文件。SassLoader
: 包含sass文件。BabelLoader
: 包含ES6文件。TypeScriptLoader
: 包含TypeScript文件。CoffeeScriptLoader
: 包含CoffeeScript文件。
每个加载器在loaders
部分下都有自己的配置。
CSS
启用加载CSS文件。
您需要
css-loader
和style-loader
节点模块才能使此功能正常工作。
webpack: loaders: css: filename: '[name].css' all_chunks: true
如果省略了 filename
和 all_chunks
,则任何 CSS 都会转换为文档中的 style 标签,而不是导出到单独的 CSS 文件中。如果指定了 output.common_id
设置(允许提取共享代码),则将自动使用 CommonsChunkPlugin。
根据指定的配置,可能需要一个或多个节点模块。
enabled:true
: style-loader, css-loaderfilename
: extract-text-webpack-plugin
Less
启用加载 less 文件。
此插件与 CSS 加载器具有完全相同的配置设置。
您需要
less-loader
、css-loader
和style-loader
节点模块才能使此功能正常工作。
webpack: loaders: less: filename: '[name].css' all_chunks: true
Sass
启用加载 sass 文件。
此插件与 CSS 加载器具有完全相同的配置设置。
您需要
sass-loader
、css-loader
和style-loader
节点模块才能使此功能正常工作。
webpack: loaders: sass: filename: '[name].css' all_chunks: true include_paths: - [include dirs for node-sass]
URL
将图像转换为 base64 代码,并将其嵌入到javascript中。
此插件仅有一个 enabled
设置。默认情况下是禁用的。
webpack: loaders: url: ~
Babel
Babel 加载器将 ECMAScript 6 代码转换为 ECMAScript 5 代码,允许它在旧浏览器中运行。加载器编译 .jsx
文件而不是 .js
文件,因为并非所有文件都需要编译。一旦 ES6 成为主流,您只需逐步将 JSX 文件重命名为 js 文件,一切应该仍然可以正常工作。
您需要
babel-loader
节点模块才能使此功能正常工作。
webpack: loaders: babel: ~
TypeScript
TypeScript 加载器将 TypeScript 2 代码转换为 JavaScript 代码,允许它在所有浏览器中运行。加载器编译 .ts
文件。
您需要
ts-loader
节点模块才能使用默认配置使此功能正常工作。
webpack: loaders: typescript: ~
您也可以配置自己的加载器
webpack: loaders: typescript: loader: some-other-typescript-loader
CoffeeScript
CoffeeScript 加载器将 CoffeeScript 转换为可移植的 (.js),允许 CoffeeScript 在每个浏览器中运行。加载器加载 .coffee
文件。
您需要 coffee-loader
webpack: loaders: coffee: ~
loader
字段可以指定任何其他 CoffeeScript 加载器,请参阅 TypeScript。
插件
webpack-bundle 软件包提供了一个简单的方法来开发和使用插件。插件简单地向生成的 webpack 配置文件中写入一些代码,通过这样做,它应该可以启用更多功能。
DefinePlugin
Define 插件允许您在应用程序中声明全局变量。有关更多信息,请参阅 defineplugin 文档。
以下示例中,假设有一个名为 "environment" 的参数,其值为 "dev"。
webpack: plugins: constants: ENVIRONMENT: %environment%
稍后,在某处资产...
// start if (ENVIRONMENT === 'dev') { console.log('Hello World!'); } // end
这些变量声明由 webpack 解析。一旦代码编译并压缩,这些变量将完全从最终代码中删除。
这意味着您的开发机器上的代码会产生类似这样的结果
// start console.log('Hello World'); // end
在生产环境中
// start // end
请注意,这些注释仅用于说明此示例。编译和压缩后的代码将不包含这些注释。
提供插件
自动加载模块并将其分配给全局变量,例如 $
(用于jQuery)。有关更多信息,请参阅提供插件文档。
在下面的示例中,假设您想通过 "$" 或 "jQuery" 访问 jQuery。您只需添加此配置,插件就会为您完成剩余工作。
plugins: provides: '$': 'jquery' 'jQuery': 'jquery'
现在,您可以在内联脚本中添加您的 JavaScript 代码,Webpack 将自动为您要求 "jquery"。
{% webpack inline %} <script type="text/javascript"> $(function () { $('[data-toggle="tooltip"]').tooltip() }) </script> {% endwebpack %}
重要
不要忘记通过 npm 安装 jQuery npm install jquery
。由于所有 node_modules
都在 webpack.config.js
中解析,它将自动找到它。
UglifyJS
在 JS 输出上运行 UglifyJS,创建更小、更优化的 JS 文件。有关更多信息,请参阅uglifyjs 文档。
plugins: uglifyjs: mangle_except: ['$super', '$', 'exports', 'require'] # Variable names to not mangle source_map: true # Generate a source map for tracking errors in compressed files. test: '/\.js($|\?)/i' # RegExp to filter processed files minimize: true # Whether to minimize or not # Options to set which optimizations UglifyJS will perform. compress: sequences: true # Join consecutive statements with the "comma operator" properties: true # Optimize property access: a["foo"] → a.foo dead_code: true # Discard unreachable code drop_debugger: true # Discard "debugger" statements unsafe: false # Perform unsafe optimizations conditionals: true # Optimize ifs and conditional expressions comparisons: true # Optimize comparisons evaluate: true # Evaluate constant expressions booleans: true # Optimize boolean expressions loops: true # Optimize loops unused: true # Drop unused variables/functions hoist_funs: true # Hoist function declarations hoist_vars: false # Hoist variable declarations if_return: true # Optimize if-s followed by return/continue join_vars: true # Join var declarations cascade: true # Try to cascade `right` into `left` in sequences side_effects: true # Drop side-effect-free statements warnings: false # Warn about potentially dangerous optimizations/code
现在,当您的 JS 文件构建完成后,将使用 UglifyJS 进行压缩和优化。