本文介绍了在现有的 PHP 和 JS 项目中使用 webpack的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有 jquery 和 bootstrap 的现有 PHP 项目,没有使用任何前端框架.

我正在尝试使用 webpack 模块打包器为我的项目资源创建单个入口点,使用 node js 包管理器管理 js 依赖项,将任务作为最小化 js css 运行,图像重新调整大小...等.并改善加载单个页面所需的浏览器加载时间.

我遇到了 webpack 教程并必须安装它并安装它的开发服务器,但问题是我无法理解我将如何转换项目中所有当前的 js 脚本和 css 链接(我在这里有很多jquery和CSS库用来在项目中提供多种功能)来使用webpack.

我是否必须以适合 webpack 的方式重写我所有的 JS 和 CSS 文件?如何成功迁移?

此外,我无法在 webpack 开发服务器上运行我当前的 php 应用程序,它是否意味着首先要在那里运行?同时只列出项目的目录.

我创建了一个测试 index.js 文件并使用以下 webpack 配置:

var path = require('path');var webpack = require('webpack');模块.exports ={入口: ['./public/js/index.js','webpack/hot/dev-server','webpack-dev-server/client?http://localhost:8080'],插件: [新的 webpack.HotModuleReplacementPlugin()],输出: {路径:path.join(__dirname, "public/dist/js"),publicPath : "http://localhost:8080/my_proj/public/dist/js",文件名:bundle.js"}};

我将 bundle.js 添加到我的脚本加载中只是为了测试如下,希望应用程序能够在 webpack 开发服务器上运行:

<script type="text/javascript" src="public/dist/js/bundle.js"></script><script type="text/javascript" src="public/js/jquery.min.js"></script><script type="text/javascript" src="public/js/jquery.migrate.js"></script><script type="text/javascript" src="public/js/jquery.bxslider.min.js"></script><script type="text/javascript" src="public/js/jquery.appear.js"></script><script type="text/javascript" src="public/js/jquery.countTo.js"></script><script type="text/javascript" src="public/js/bootstrap.js"></script>

请帮助我理解这里的概念以及我如何才能成功迁移?

解决方案

首先,回答您的小问题:

  • 不,您不应该通过 webpack 开发服务器运行您的 PHP 应用程序.在下面的实时重新加载部分进行了解释.
  • 不,您不必重写资产.大概.请参阅下面的 CSSEdge Cases 部分.

免责声明:我只回答你问题的一小部分.它的范围实在是太广泛了,不能只包含在一个 StackOverflow 答案中.

我只会联系

  • 为 webpack 设置开发和生产环境
  • 捆绑你的第一个 JavaScript

这应该为您奠定基础.

我还会提到一些您可能想要添加的内容,并根据资源链接以通读.

那么,我们走吧.

要求

我假设您的机器上安装了 Node.js 和 npm,并且大致知道如何使用它们.

我还假设您已将 webpackwebpack-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 = {//我们将在这里放置所有环境的 webpack 配置}

该文件现在显然只是导出一个空对象,但我们在以下步骤中需要它.

将此代码放入您的build/config.production.js:

const { merge } = require('webpack-merge')module.exports = merge(require('./config.base.js'), {模式:'生产'//我们将在此处放置生产环境的 webpack 配置})

几乎相同的代码进入你的build/config.development.js:

const { merge } = require('webpack-merge')module.exports = merge(require('./config.base.js'), {模式:'发展',观看:真实//开发环境的所有 webpack 配置都会放在这里})

我想这是非常直观的:

使用带有 config.development.js 配置的 webpack 将获取公共配置并合并它自己的配置声明.

更新:上述配置文件中的 mode 选项是在 webpack 4(2018 年 2 月发布)中添加的.它为开发和生产包设置了一堆合理的默认值.

现在从命令行运行该进程将如下所示:

npx webpack --config build/config.development.js# 如果上述方法不起作用,您可能安装了旧版本的 npm (

...对于生产环境,反之亦然.

该命令使用起来相当笨拙,但不用担心,我们稍后会解决这个问题.

制作一些帮助文件

我们希望将某些信息集中起来,以便于交换.文件路径就是这样.所以让我们提取它们.

在您的 build 文件夹中创建一个 paths.js 并让它导出一些我们稍后要使用的路径:

const path = require('path')//我真的只是通过阅读您的问题来猜测您项目的文件夹结构,//您可能想要调整整个部分模块.出口 = {//源文件的基本路径,尤其是 index.jssrc: path.resolve(__dirname, '..', 'public'),//放置生成包的路径DIST: path.resolve(__dirname, '..', 'public', 'dist'),/*这是你的公共路径.如果您在 http://example.com 上运行您的应用程序并且我正确设置了您的 DIST 文件夹,它只是/dist".但是,如果您在 http://localhost/my/app 本地运行它,它将是/my/app/dist".这意味着您应该*不*在此处硬编码该路径,而是将其写入机器相关的配置文件.(如果你还没有这样的东西,谷歌搜索dotenv"或类似的东西.)*/资产:'/dist'}

创建别名

如上所述,从技术上讲,我们可以在 development 模式下运行我们的构建链,如下所示:

npx webpack --config build/config.development.js

虽然这是一个令人不舒服的冗长命令,所以让我们改变它.

通过 npm 脚本运行构建过程更方便.将每个环境的一个脚本添加到您的 package.json 中,如下所示:

{脚本":{dev":webpack --config build/config.development.js",prod":webpack --config build/config.production.js"}}

现在您可以使用 npm run dev 来运行您的构建链.npm run prod - 更容易记忆,输入速度更快.

...当然,只要有任何东西要构建.

捆绑 JavaScript

好的,到目前为止,这实际上是相当多的工作,没有取得太多成果.

那么让我们从更令人兴奋的事情开始:我们将定义一个 JavaScript 入口点.

定义入口点

将以下代码放入您的 build/config.base.js(完全替换现有代码):

const path = require('path')const { SRC, DIST, ASSETS } = require('./paths')模块.出口 = {入口: {脚本:path.resolve(src, 'js', 'index.js')},输出: {//把所有捆绑的东西放在你的 dist 文件夹中路径:DIST,//我们上面的单一入口点将被命名为scripts.js";文件名:'[名称].js',//从我们在浏览器中访问的域看到的输出路径公共路径:资产}}

创建 JavaScript 文件

上述配置要求 index.js 位于您的 SRC/js 文件夹中(如 build/paths.js 中所定义)).

让我们使用以下内容创建该文件:

import './jquery.min.js'导入'./jquery.migrate.js'导入'./jquery.bxslider.min.js'导入'./jquery.appear.js'导入'./jquery.countTo.js'导入'./bootstrap.js'

如您所见,index.js 仅导入您要使用的所有文件.

如果你现在运行

npm run prod

在您的终端中,将在您的 DIST 文件夹中创建一个 scripts.js 文件.您可以使用普通的 <script> 标签将其包含到您的标记中.

恭喜,你已经有了一个有效的 webpack 设置!

深入研究

这个迷你教程只是简单地介绍了 webpack 可以做的事情.它为您的配置提供了一个非常坚实的基础,您现在可以填充您需要的任何内容.这实际上会涉及很多东西.

我将列出一些您可能想要增强的内容,并附有一些链接供您通读.

webpack 概念

如果你想使用 webpack,如果你不了解它的底层概念,可能很难做到.Juho Vepsäläinen 创建了一个很好的 webpack 入门指南,对我帮助很大.他还是 webpack 核心贡献者,所以你可以确定他知道他在说什么.

特别是加载器是一个您确实需要了解的概念.

此列表中的许多提示也在此处进行了解释.

阅读更多:SurviveJS – webpack 教程

代码拆分

正如其名:您可能不想将所有 JavaScript 打包到一个庞大的输出文件中.

webpack 的工作是将你的 bundle 中的一部分拆分出来,你只需要在应用程序的某些页面上使用这些部分.

此外,根据您处理项目 JavaScript 的频率,将第三方代码从包中分离出来用于缓存可能是个好主意.

阅读更多:webpack 文档 - 代码拆分

缓存

您可能希望通过向捆绑文件名添加哈希来增强站点的缓存行为,这取决于它们的内容.这将创建(例如)一个 script.31aa1d3cad014475a618.js 而不是 scripts.js.

该文件可以无限期地缓存,因为一旦其内容发生变化,文件名也会随之变化.

然后您的 PHP 代码可能会使用 webpack-manifest-plugin 来访问生成的文件名.

阅读更多:

转译

如果您想在站点的 JavaScript 中使用现代 ES2015 代码(并且针对非常绿浏览器),您需要将它们转换为常规 ES5.(如果ES2015"这个词对你来说没有任何意义,你很可能没有使用它,可以忽略这一段.)

阅读更多:babel-loader – 一个在你的系统上运行 Babel 的加载器脚本

CSS

有用于 CSS 的 webpack 加载器.还有萨斯.和 PostCSS.无论您需要什么.

而且由于您可能不打算通过 标签包含 CSS,请了解 Extract Text Plugin 以生成实际的 .css 文件.

更新:提取文本插件非常成熟.然而,它实际上是一种 hack:即使 webpack 只知道 JavaScript 作为其目标语言,它也会生成 .css 文件.

然而,从 webpack 4 开始,这不再正确.现在有一个系统可以定义任意模块类型,包括 CSS.

长话短说:期待 webpack 中的原生 CSS 支持来取代 提取文本插件很快.

提示:路径

我会提到这一点,因为这对我来说是一个真正的痛点,直到我意识到 webpack 在这里是如何工作的:

请注意,webpack 会识别您的 url(...) 语句并尝试解析它们相对于您的源文件.

这意味着,你的源文件public/css/main.css:

body {背景: url('../img/bg.jpg');}

如果你的输出路径是public/dist/css/bundle.css,会转化为:

body {背景: url('../../img/bg.jpg');}

阅读更多:

缩小

更新:自 webpack 4 于 2018 年 2 月发布以来,本节已相当过时.将新的 mode 选项设置为 production" 现在会自动应用 JavaScript 缩小.

webpack 有一个 Terser 插件来缩小你的 JavaScript.缩小 CSS 是上述 css-loader 插件的内置功能.

阅读更多:Terser webpack 插件

图像优化

webpack 是一个打包器,而不是任务运行器.因此,图像优化不是真正的 webpack 任务.您最好使用实际的任务运行器或为此定义一些 npm 脚本.

这并不意味着 webpack 没有能力做到这一点.几乎所有东西都有插件.

阅读更多:

实时重新加载

实时重新加载的问题有一个非常简单的原因:webpack 开发服务器只是一个简单的 Node.js 服务器,仅提供静态文件.

就您而言,webpack-dev-server 可能根本是错误的工具.尝试使用 webpack-livereload-plugin 代替您可以通过 标签包含的实时重新加载器.

阅读更多:webpack-livereload-plugin

源地图

更新:从 webpack 4(2018 年 2 月发布)开始,当新的 mode 选项设置为 development" 时,会自动生成源映射..

无论如何,请使用源映射.它们将使您的捆绑工作变得更加轻松,您会想哭.

阅读更多:webpack 文档 - 源地图

边缘情况

通常,您将使用 webpack 处理的所有现有脚本都应该运行良好.

我现在想到的唯一例外是关于全局实体.

看下面的代码:

function myFunc() {console.log('我存在!')}

纯 JavaScript 文件中的这段代码将使 myFunc 在您的 JS 代码中随处可用.但是由于 webpack bundle 代码被包装在回调函数中(因此离开了全局作用域),将无法再访问该函数.

第三方库在那里应该没有问题,他们通常将全局变量直接分配给 window 对象,但是如果您已经在项目中编写了 JS 代码,您应该意识到这一点.

自动化!

您会希望尽可能多地自动化您的工作流程.

考虑在推前/拉后通过 git hook 运行 npm run prod.


希望这会有所帮助.

I have an existing PHP project with jquery and bootstrap, not using any front-end framework.

I am trying to use webpack module bundler in order to create a single entry point for my project resources, manage js dependencies with node js package manager, run tasks as minify js css, image re-size...etc. And improve the browser loading time required to load a single page.

I came across the webpack tutorials and got to install it and install its dev-server, but the problem is that I am not able to understand how I will convert all my current js scripts and css links in the project (where I have a lot of jquery and CSS libraries used to provide multiple features in the project) to use webpack.

Do I have to rewrite all my JS and CSS files in a way that suits webpack? How do I make a successful migration?

Besides, I am not able to run my current php application on the webpack dev-server, is it meant to run there in the first place? It is only listing the directories of the project in the meantime.

I have created a test index.js file and used the following webpack configuration:

var path = require('path');
var webpack = require('webpack');

module.exports =
{
    entry: [
        './public/js/index.js',
        'webpack/hot/dev-server',
        'webpack-dev-server/client?http://localhost:8080'
    ],
    plugins: [
      new webpack.HotModuleReplacementPlugin()
    ],
    output: {
        path: path.join(__dirname, "public/dist/js"),
        publicPath : "http://localhost:8080/my_proj/public/dist/js",
        filename: "bundle.js"
    }

};

I added the bundle.js to my script loads just for testing as follows hoping that the application will run on the webpack dev-server:

<script type="text/javascript" src="public/dist/js/bundle.js"></script>
<script type="text/javascript" src="public/js/jquery.min.js"></script>
<script type="text/javascript" src="public/js/jquery.migrate.js"></script>
<script type="text/javascript" src="public/js/jquery.bxslider.min.js"></script>
<script type="text/javascript" src="public/js/jquery.appear.js"></script>
<script type="text/javascript" src="public/js/jquery.countTo.js"></script>
<script type="text/javascript" src="public/js/bootstrap.js"></script>

Please help me understand the concept here and how can I make this migration successfully?

解决方案

First, to answer your smaller questions:

  • No, you're not supposed to run your PHP application through a webpack dev server. Explained in the Live Reloading section below.
  • No, you won't have to rewrite your assets. Probably. See the CSS and Edge Cases sections below.

Disclaimer: I'll only take on a small fraction of your question. Its scope is just way too broad to be packed into just one StackOverflow answer.

I will only get in touch with

  • setting up a development and a production environment for webpack
  • bundling your first JavaScript

which should give you a foundation to build on.

I'll also mention some things you may want to add and link according resources to read through.

So, let's go.

Requirements

I assume you have Node.js and npm installed on your machine and roughly know how to use them.

I also assume you have webpack and webpack-cli installed as (dev) dependencies of your project (not just globally):

npm install --save-dev webpack webpack-cli

Set up development and a production workflow

You usually want to do stuff differently in development than in production (minifying in production, live-reloading in development, ...)

To achieve that, we'll want to split up our configuration files.

Prepare the directory structure

Let's agree to ignore the webpack config from your question. We'll start all over, we'd have to change almost everything anyway.

First, create a build folder inside your project root. Build-related stuff will go there, since we don't want to pollute your project's root folder with config files. (You're free to name this folder differently, but keep track of that during this tutorial.)

Create a config.base.js, a config.production.js and a config.development.js file inside that folder.

Great, we have config files for two build chains now. The configurations are still empty though, so let's now fill them with some basic logic.

Install webpack-merge

But first, we'll need to install webpack-merge.

npm install --save-dev webpack-merge

This package allows us to deeply merge multiple webpack configurations. We want to use it to create webpack configurations depending on our current environment.

Adjust your configuration

Now adjust your build/config.base.js:

module.exports = {
  // We'll place webpack configuration for all environments here
}

The file does obviously just export an empty object right now, but we'll need that for the following steps.

Put this code in your 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
})

And almost the same code goes into your 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
})

I guess it's pretty intuitive what this does:

Using webpack with the config.development.js configuration will fetch the common configuration and merge its own config declaration in.

Now running the process would look like this from the command line:

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

...and vice versa for the production environment.

That command is rather clunky to use, but no worries, we'll address that later.

Make some helper files

There are information we'll be wanting to centralize to make them easily exchangeable. File paths are such a thing. So let's extract them.

Create a paths.js in your build folder and have it export some paths we'll want to use later:

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'
}

Create aliases

As mentioned above, we could technically run our build chain in development mode like this:

npx webpack --config build/config.development.js

That's an uncomfortably verbose command though, so let's change that.

It's way more convenient to run your build process via npm scripts. Add one script per environment to your package.json like this:

{
  "scripts": {
    "dev": "webpack --config build/config.development.js",
    "prod": "webpack --config build/config.production.js"
  }
}

Now you can run your build chains with npm run dev resp. npm run prod – which is much easier to memorize and faster to type.

...as soon as there'es anything to build, of course.

Bundle JavaScript

Okay, that was actually a fair amount of work without achieving too much so far.

So let's start with something more exciting: We'll define a JavaScript entry point.

Define an entry point

Put the following code into your build/config.base.js (replacing the existing code entirely):

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
  }
}

Create the JavaScript file

The above configuration expects an index.js to live in your SRC/js folder (as defined in the build/paths.js).

Let's create that file with the following content:

import './jquery.min.js'
import './jquery.migrate.js'
import './jquery.bxslider.min.js'
import './jquery.appear.js'
import './jquery.countTo.js'
import './bootstrap.js'

As you can see, the index.js just imports all of the files you want to use.

If you now run

npm run prod

from your terminal, a scripts.js file will be created in your DIST folder. You can include that into your markup with a plain ol' <script> tag.

Congratulations, you've got a working webpack setup!

Dive deeper

This mini-tutorial really just scraped the surface of what you can do with webpack. It gives you a pretty solid foundation for your configuration which you now can fill with whatever you need. And that will actually be quite a lot of stuff.

I'll list a few more things you may want to enhance, with some links to read through.

webpack Concepts

If you want to use webpack, it can be hard to do so if you don't know about its underlying concepts. Juho Vepsäläinen created a great guide on getting started with webpack which helped me a whole lot. He's also a webpack core contributor so you can be sure he knows what he's talking about.

Especially loaders are a concept you'll really need to know.

Many of the hints on this list are also explained there.

Read more: SurviveJS – webpack tutorial

Code Splitting

It does what the name's saying: You might not want to pack all your JavaScript into one bulky output file.

It's a job webpack does for you to split off parts of your bundle which you only need on certain pages of your application.

Also, depending on how frequently you're working on your project's JavaScript, it might be a good idea to split off third party code from your bundle for caching purposes.

Read more: webpack Documentation – Code Splitting

Caching

You may want to enhance your site's caching behaviour by adding a hash to your bundled file names which depends on their content. This will create (for example) a script.31aa1d3cad014475a618.js instead of a scripts.js.

That file can then be cached indefinitely because as soon as its contents change, the file name will change as well.

Your PHP code might then use the webpack-manifest-plugin to gain access to the generated file names.

Read more:

Transpiling

In case you want to use modern ES2015 code in your site's JavaScript (and are targeting non-evergreen browsers), you'll want to transpile them down to regular ES5. (If the term "ES2015" does not make any sense to you, you're most likely not using it and can ignore this paragraph.)

Read more: babel-loader – A loader that runs Babel on your scripts

CSS

There are webpack loaders for CSS. And Sass. And PostCSS. Whatever you need.

And since you're probably not planning to include your CSS via <script> tags, get to know the Extract Text Plugin to generate actual .css files.

Hint: Paths

I'll mention this because this was a real pain point for me until I realized how webpack works here:

Be aware that webpack will recognize your url(...) statements and try to resolve them relative to your source files.

This means, your source file public/css/main.css:

body {
  background: url('../img/bg.jpg');
}

if your output path is public/dist/css/bundle.css, will be transformed to:

body {
  background: url('../../img/bg.jpg');
}

Read more:

Minifying

There is a Terser plugin for webpack to minify your JavaScript. Minifying CSS is a feature already builtin to the css-loader plugin mentioned above.

Read more: Terser webpack Plugin

Image Optimization

webpack is a bundler, not a task runner. Thus, image optimization is not a genuine webpack task. You'd probably be better off using an actual task runner or just defining some npm scripts for this.

This does not mean webpack is not capable of doing this. There are plugins for pretty much everything.

Read more:

Live Reloading

Your problems with live reloading have a pretty simple cause: a webpack dev server is just a simple Node.js server serving only static files.

For you're case, webpack-dev-server probably is the wrong tool at all. Try webpack-livereload-plugin instead for a live reloader that you can just include via <script> tag.

Read more: webpack-livereload-plugin

Source Maps

By all means, use source maps. They'll make your work with bundles so much easier you'll want to cry.

Read more: webpack Documentation – Source Maps

Edge Cases

Usually, all your existing scripts you'll process with webpack should be running just fine.

The only exception that comes to my mind right now would be regarding global entities.

Look at the following code:

function myFunc () {
  console.log('I exist!')
}

This code in a plain JavaScript file would make myFunc available everywhere in your JS code. But since webpack bundle code is wrapped inside callback functions (and thus leaving the global scope), there won't be any access to that function anymore.

Third party libraries should not be a problem there, they usually assign their globals to the window object directly, but if you've already written JS code in your project, you should be aware of that.

Automate!

You'll want to automate as much of your workflow as possible.

Consider running npm run prod via a git hook before pushing / after pulling.


Hope this helps.

这篇关于在现有的 PHP 和 JS 项目中使用 webpack的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-26 04:29