首先,回答您的小问题:
- 不,您不应该通过 webpack 开发服务器运行 PHP 应用程序。在下面的实时重新加载部分中进行了说明。
- 不,您不必重写资产。大概。请参阅下面的 CSS 和 Edge Cases 部分。
免责声明:我只会回答您的一小部分问题。它的范围太广了,无法仅包含在一个 StackOverflow 答案中。
我只会联系
- 为 webpack 设置开发和生产环境
- 捆绑您的第一个 JavaScript
这应该会给你一个基础。
我还会提到一些您可能想要添加和链接的内容,以供阅读。
那么,我们走吧。
要求
我假设你的机器上安装了 Node.js 和 npm,并且大致知道如何使用它们。
我还假设您已将 webpack 和 webpack-cli 安装为项目的(开发)依赖项(不仅仅是全局):
npm install --save-dev webpack webpack-cli
更新:此答案的早期版本不需要安装webpack-cli。从版本 4(2018 年 2 月)开始,webpack 的 CLI 驻留在自己的包中,因此需要额外的包。
设置开发和生产工作流程
您通常希望在开发和生产中做不同的事情(在生产中缩小,在开发中实时重新加载......)
为此,我们需要拆分配置文件。
准备目录结构
让我们同意忽略您的问题中的 webpack 配置。我们将重新开始,无论如何我们都必须改变几乎所有东西。
首先,在您的项目根目录中创建一个build 文件夹。与构建相关的东西会放在那里,因为我们不想用配置文件污染项目的根文件夹。 (您可以随意命名此文件夹,但在本教程中请注意。)
在该文件夹中创建一个config.base.js、一个config.production.js 和一个config.development.js 文件。
太好了,我们现在有两个构建链的配置文件。虽然配置仍然是空的,所以现在让我们用一些基本逻辑来填充它们。
安装webpack-merge
但首先,我们需要安装webpack-merge。
npm install --save-dev webpack-merge
这个包允许我们深度合并多个 webpack 配置。我们想使用它来根据我们当前的环境创建 webpack 配置。
调整你的配置
现在调整你的build/config.base.js:
module.exports = {
// We'll place webpack configuration for all environments here
}
该文件现在显然只是导出了一个空对象,但我们在接下来的步骤中需要它。
将此代码放入您的build/config.production.js:
const { merge } = require('webpack-merge')
module.exports = merge(require('./config.base.js'), {
mode: 'production'
// We'll place webpack configuration for production environment here
})
几乎相同的代码进入您的build/config.development.js:
const { merge } = require('webpack-merge')
module.exports = merge(require('./config.base.js'), {
mode: 'development',
watch: true
// All webpack configuration for development environment will go here
})
我想这很直观:
使用带有 config.development.js 配置的 webpack 将获取通用配置并将其自己的配置声明合并到其中。
更新: webpack 4(2018 年 2 月发布)中添加了上述配置文件中的 mode 选项。它为开发和生产包设置了a bunch of sensible defaults。
现在从命令行运行该进程将如下所示:
npx webpack --config build/config.development.js
# If the above doesn't work, you probably have an older version of npm (< 5.1) installed
# While npx is a really great tool, you can of course still call the path of the webpack executable manually:
node_modules/.bin/webpack --config build/config.development.js
...对于production 环境,反之亦然。
该命令使用起来相当笨拙,但不用担心,我们稍后会解决这个问题。
制作一些帮助文件
我们希望集中一些信息以使它们易于交换。文件路径就是这样的东西。所以让我们提取它们。
在您的 build 文件夹中创建一个 paths.js 并让它导出一些我们以后要使用的路径:
const path = require('path')
// I'm really just guessing your project's folder structure from reading your question,
// you might want to adjust this whole section
module.exports = {
// The base path of your source files, especially of your index.js
SRC: path.resolve(__dirname, '..', 'public'),
// The path to put the generated bundle(s)
DIST: path.resolve(__dirname, '..', 'public', 'dist'),
/*
This is your public path.
If you're running your app at http://example.com and I got your DIST folder right,
it'll simply be "/dist".
But if you're running it locally at http://localhost/my/app, it will be "/my/app/dist".
That means you should probably *not* hardcode that path here but write it to a
machine-related config file. (If you don't already have something like that,
google for "dotenv" or something similar.)
*/
ASSETS: '/dist'
}
创建别名
如上所述,从技术上讲,我们可以像这样在development 模式下运行我们的构建链:
npx webpack --config build/config.development.js
虽然这是一个令人不安的冗长命令,所以让我们改变它。
通过npm 脚本运行构建过程更加方便。为每个环境添加一个脚本到您的 package.json,如下所示:
{
"scripts": {
"dev": "webpack --config build/config.development.js",
"prod": "webpack --config build/config.production.js"
}
}
现在您可以使用 npm run dev resp 运行您的构建链。 npm run prod – 更容易记忆,打字更快。
...当然,只要有任何东西要构建。
捆绑 JavaScript
好吧,这实际上是相当多的工作,到目前为止还没有取得太多成果。
让我们从更令人兴奋的事情开始:我们将定义一个 JavaScript 入口点。
定义入口点
将以下代码放入您的build/config.base.js(完全替换现有代码):
const path = require('path')
const { SRC, DIST, ASSETS } = require('./paths')
module.exports = {
entry: {
scripts: path.resolve(SRC, 'js', 'index.js')
},
output: {
// Put all the bundled stuff in your dist folder
path: DIST,
// Our single entry point from above will be named "scripts.js"
filename: '[name].js',
// The output path as seen from the domain we're visiting in the browser
publicPath: ASSETS
}
}
创建 JavaScript 文件
上述配置要求index.js 存在于您的SRC/js 文件夹中(如build/paths.js 中所定义)。
让我们创建具有以下内容的文件:
import './jquery.min.js'
import './jquery.migrate.js'
import './jquery.bxslider.min.js'
import './jquery.appear.js'
import './jquery.countTo.js'
import './bootstrap.js'
如您所见,index.js 只是导入您要使用的所有文件。
如果你现在运行
npm run prod
在您的终端中,将在您的 DIST 文件夹中创建一个 scripts.js 文件。您可以使用普通的 ol' <script> 标记将其包含到您的标记中。
恭喜,您的 webpack 设置已正常运行!
深入研究
这个迷你教程实际上只是简单地介绍了您可以使用 webpack 做什么。它为您的配置提供了非常坚实的基础,您现在可以根据需要填写任何内容。这实际上会是很多东西。
我将列出一些您可能想要增强的内容,并提供一些链接供您阅读。
webpack 概念
如果你想使用 webpack,如果你不了解它的基本概念,可能很难做到。 Juho Vepsäläinen 创建了一个很棒的 webpack 入门指南,对我帮助很大。他也是 webpack 核心贡献者,所以你可以确定他知道他在说什么。
尤其是 loaders 是您真正需要了解的概念。
此列表中的许多提示也在此处进行了说明。
阅读更多:SurviveJS – webpack tutorial
代码拆分
顾名思义:您可能不想将所有 JavaScript 打包到一个庞大的输出文件中。
这是 webpack 所做的一项工作,你可以拆分你只在应用程序的某些页面上需要的部分捆绑包。
此外,根据您处理项目 JavaScript 的频率,最好将第三方代码从包中分离出来以进行缓存。
阅读更多:webpack Documentation – Code Splitting
缓存
您可能希望通过为捆绑的文件名添加一个哈希值来增强您网站的缓存行为,这取决于它们的内容。这将创建(例如)script.31aa1d3cad014475a618.js 而不是scripts.js。
然后可以无限期地缓存该文件,因为一旦其内容更改,文件名也会更改。
然后,您的 PHP 代码可能会使用 webpack-manifest-plugin 来访问生成的文件名。
阅读更多:
转译
如果您想在网站的 JavaScript 中使用现代 ES2015 代码(并且针对非常青浏览器),您需要将它们转换为常规 ES5。 (如果“ES2015”这个词对你没有任何意义,你很可能没有使用它,可以忽略这一段。)
阅读更多:babel-loader – A loader that runs Babel on your scripts
CSS
有用于 CSS 的 webpack 加载器。还有萨斯。和 PostCSS。无论您需要什么。
由于您可能不打算通过 <script> 标签包含 CSS,因此请了解 Extract Text Plugin 以生成实际的 .css 文件。
更新:提取文本插件非常成熟。然而,它实际上是一种 hack:它生成 .css 文件,尽管 webpack 只知道 JavaScript 作为它的目标语言。
但是,从 webpack 4 开始,这不再适用。现在有一个系统可以定义任意模块类型,包括 CSS。
长话短说:Expect native CSS support in webpack to replace Extract Text Plugin some time soon。
提示:路径
我会提到这一点,因为这对我来说是一个真正的痛点,直到我意识到 webpack 在这里是如何工作的:
请注意,webpack 会识别您的 url(...) 语句并尝试解析它们相对于您的源文件。
这意味着,你的源文件public/css/main.css:
body {
background: url('../img/bg.jpg');
}
如果你的输出路径是public/dist/css/bundle.css,将转换为:
body {
background: url('../../img/bg.jpg');
}
阅读更多:
缩小
更新: 由于 webpack 4 于 2018 年 2 月发布,本节已经过时。将新的 mode 选项设置为 "production" 现在会自动应用 JavaScript 缩小。
有一个用于 webpack 的 Terser 插件来缩小你的 JavaScript。缩小 CSS 是上面提到的 css-loader 插件中已经内置的一项功能。
阅读更多:Terser webpack Plugin
图像优化
webpack 是一个打包器,而不是一个任务运行器。因此,图像优化并不是真正的 webpack 任务。您最好使用实际的任务运行程序或为此定义一些 npm 脚本。
这并不意味着 webpack 无法做到这一点。几乎所有东西都有插件。
阅读更多:
实时重新加载
您的实时重新加载问题有一个非常简单的原因:webpack 开发服务器只是一个仅提供静态文件的简单 Node.js 服务器。
对于您而言,webpack-dev-server 可能根本是错误的工具。尝试使用webpack-livereload-plugin 代替实时重新加载器,您可以通过<script> 标签包含它。
阅读更多:webpack-livereload-plugin
源地图
更新:从 webpack 4(2018 年 2 月发布)开始,当新的 mode 选项设置为 "development" 时,会自动生成源映射。
请务必使用源地图。它们将使您使用捆绑包的工作变得更加轻松,您会想哭。
阅读更多:webpack Documentation – Source Maps
边缘案例
通常,您将使用 webpack 处理的所有现有脚本都应该可以正常运行。
我现在想到的唯一例外是关于全局实体。
看下面的代码:
function myFunc () {
console.log('I exist!')
}
纯 JavaScript 文件中的这段代码将使 myFunc 在您的 JS 代码中随处可用。但是由于 webpack 包代码被包装在回调函数中(因此离开了全局范围),将不再有对该函数的任何访问。
第三方库应该不成问题,他们通常将全局变量直接分配给window 对象,但如果您已经在项目中编写过 JS 代码,则应该注意这一点。
自动化!
您会希望尽可能多地自动化您的工作流程。
考虑在推前/拉后通过 git 钩子运行 npm run prod。
希望这会有所帮助。