资讯专栏INFORMATION COLUMN

一个现代化的webpack工程初建

MyFaith / 1815人阅读

摘要:一前言文章介绍了一个现代化的项目的环境是什么样的。其中一个就是引用路径的问题。扩展将多带带打包详细介绍见这是一个插件,可以简化创建文件以便为包提供服务。两种环境的配置在中都支持的配置具体的默认配置查询可以移步这里的默认设置。

一 前言

文章介绍了一个现代化的项目的webpack4环境是什么样的。这里只是介绍了基础的功能,如果需要详细的相关只是可以去webpack官网去查阅。
代码地址:github
环境特点:
1.使用了webpack-dev-middleware,在文件内容更改之后自动编译;
2.使用了webpack-hot-middleware,在热编译之后会自动刷新页面更改的内容,而不是刷新整个页面
3.使用了server.js文件来自己控制启动http服务,后期可以扩展简单的后端功能

文章将webpack的配置文件写成了三份:公用部分文件、开发环境文件、线上环境文件,具体在文章中会有详细的介绍。

注意:文章介绍很详细,适合新手入门使用,请耐心阅读。

二 正文 1.path相关内容

文档:http://nodejs.cn/api/path.html
我们经常用到的就是path.resolve和path.join,那么我们就讲一下两者的用法和区别:
相关文章:Difference between path.resolve and path.join invocation?

(1)path.join
path.join() 方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径。

path.join("/a", "/b") // Outputs "/a/b"
path.join("/foo", "bar", "baz/asdf", "quux", ".."); // outputs "/foo/bar/baz/asdf"

summary:path.join通常用到的是简单的将字符串进行拼接。
(2)path.resolve
path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径
给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径(就会停止解析)

例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve("/foo", "/bar", "baz") 会返回 /bar/baz。

如果处理完全部给定的 path 片段后还未生成一个绝对路径,则当前工作目录会被用上。
生成的路径是规范化后的,且末尾的斜杠会被删除,除非路径被解析为根目录。
长度为零的 path 片段会被忽略。
如果没有传入 path 片段,则 path.resolve() 会返回当前工作目录的绝对路径。
例子:

path.resolve("/foo/bar", "./baz");
// 返回: "/foo/bar/baz"

path.resolve("/foo/bar", "/tmp/file/");
// 返回: "/tmp/file

(3)work directory 与 dirname
工作目录和文件目录并不是一直相等,我们以"./src/view/index.js"文件为例:
文件目录是固定的,就是文件所在的目录:./src/view/index.js
工作目录是不确定的,查看当前所在目录:pwd

如果你是在./src/view/ 下执行的index.js,那么就和文件路径相同./src/view/index.js
但是如果你在./src下执行的index.js,那工作路径则是./src
2.从server.js谈起

我们要知道server.js都做了些什么:

1.开启一个http服务器
2.使用热编译中间件,实时编译修改过的内容
3.使用热替换,实时查看最新的页面UI
4.【扩展】可以做一些后端的东西

代码如下:

const http = require("http");
const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");

// 使用express启用一个服务器
const express = require("express");

// 引用开发环境下的webpack配置文件
const config = require("./webpack.dev");
const app = express();
const webpackConfig = webpack(config);
const devMiddlewareCompiler = webpackDevMiddleware(webpackConfig,{
    publicPath:config.output.publicPath
});
const hotMiddlewareCompiler = webpackHotMiddleware(webpackConfig,{
    log: false,
    heartbeat: 2000,
 })

app.use(devMiddlewareCompiler);// 使用热编译中间件
app.use(hotMiddlewareCompiler);// 使用热替换中间件

app.listen(8080,function(){
    console.log("Example app listening on port 8080!
");
});

注意:为什么要把热编译的功能放在node里面呢?如果引用wepack-dev-server会自动管理热编译,它的原理也还是利用express开启了一个小型服务器,只不过我们看不到它。所以如果你要自己控制,并且想简单方便的在后端做点小东西,可以完全使用上面的方法。如果是后端比较重就不建议这么写了,你需要开启两台服务,通过代理的方式模拟进行前后端通信了。

3.webpack common

webpack.common,js配置了无论是开发还是发布都需要的东西,比如一些loader的转译,代码的打包压缩等。
具体代码如下:

const path = require("path");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: {
    app: "./src/index.js" // 入口文件index.js
  },
  module:{
    rules:[{
        test:/.css$/,
        use:[
          "style-loader",
          "css-loader"
        ],
    },
    {
       test: /.(png|svg|jpg|gif)$/,
       use: [
         "file-loader"
       ]
     },
      {
           test: /.(woff|woff2|eot|ttf|otf)$/,
           use: [
             "file-loader"
           ]
      }
  ],
},
  plugins: [
    new CleanWebpackPlugin(["dist"]),
    new HtmlWebpackPlugin({
      title: "Production"
    }),
  ],
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
  }
};

下面讲一讲主要做了什么事:

3-1 file-loader

a. 加载图片
如果我们要想像引用模块那样引用一个图片,例如:

import Rose from "./img/rose.jpg"

在 webpack 里负责图片翻译的是 file-loader。而且,webpack 在最终构建时,会自动将模块中引用的图片拷贝到相应目录。如果你检查此元素,你将看到实际的文件名已更改为像 5c999da72346a995e7e2718865d019c8.png 一样。这意味着 webpack 在 src 文件夹中找到我们的文件,并成功处理过它!

b. 加载字体
css文件中引用字体:

 @font-face {
   font-family: "MyFont";
  src:  url("./my-font.woff2") format("woff2"),
         url("./my-font.woff") format("woff");
   font-weight: 600;
   font-style: normal;
 }

【扩展】file-loader与url-loader
如果我们希望在页面引入图片(包括img的src和background的url)。当我们基于webpack进行开发时,引入图片会遇到一些问题。其中一个就是引用路径的问题。拿background样式用url引入背景图来说,我们都知道,webpack最终会将各个模块打包成一个文件,因此我们样式中的url路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会导致图片引入失败。这个问题是用file-loader解决的,file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。另外,如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。

//url-loader封装了file-loader。url-loader不依赖于file-loader,即使用url-loader时,只需要安装url-loader即可
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /.(png|jpg|gif)$/,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 8192
            }
          }
        ]
      }
    ]
  }
}

3-2 css loader与style-loader
如果你在JS中使用:

import "./index.css"

我们需要 CSS 加载器:

(1) css-loader - 预处理 CSS 文件
(2) style-loader - 将 CSS 插入到 DOM 中的 style 标签

要查看 webpack 做了什么,请检查页面(不要查看页面源代码,因为它不会显示结果),并查看页面的 head 标签。它应该包含我们在 index.js 中导入的 style 块元素:

注意:
(1)加载器的顺序是从后往前的,loader 的顺序很重要:如果把 style-loader 放到 css-loader 后面,我们就会撞见错误。
(2)我们如果只使用了 css-loader,则 webpack 只是将 CSS 文件预处理成模块然后打包到构建文件中,并不会插入到页面。

【扩展】将CSS多带带打包:
webpack1/2/3:extract-text-webpack-plugin
webpack4:mini-css-extract-plugin

3-3 htm-lwebpack-plugin
详细介绍见:html-webpack-plugin npm
这是一个webpack插件,可以简化创建HTML文件以便为webpack包提供服务。 这对于webpack包来说特别有用,它在文件名中包含一个hash,用于更改每个编译。 你可以让插件为你生成一个HTML文件,使用lodash模板提供你自己的模板或使用你自己的加载器。

3-4 clean-webpack-plugin
详细介绍见:clean-wenpack-plugin
一个在创建之前清除你build文件夹的webpack插件。在打包生成新的build文件的时候清除之前生成的,这非常有用。

4.webpack development

两种环境的配置在webpack4中都支持mode的配置:development/production,具体的默认配置查询可以移步这里:webpack4 Mode的默认设置 。

webpack.dev.config.js:

 const webpack = require("webpack");
 const merge = require("webpack-merge");
 const common = require("./webpack.common.js");

 module.exports = merge(common, {
    mode:"development",
    plugins:[
      new webpack.NamedModulesPlugin(),
      new webpack.HotModuleReplacementPlugin(),
   ]
 });

这里做了两件事:
(1)mode:"development":定义环境为开发环境。在webpack4之后省了很多操作,只需要指定为开发环境,就会自动设定source map等信息
(2)HotModuleReplacementPlugin:模块热替换
使用热替换需要两步:

首先: Add the following plugins to the plugins array

plugins: [
    // OccurenceOrderPlugin is needed for webpack 1.x only
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    // Use NoErrorsPlugin for webpack 1.x
    new webpack.NoEmitOnErrorsPlugin()
]
Occurence ensures consistent build hashes, hot module replacement is somewhat self-explanatory, no errors is used to handle errors more cleanly.

其次:Add "webpack-hot-middleware/client" into the entry array.

This connects to the server to receive notifications when the bundle rebuilds and then updates your client bundle accordingly.
5.webpack production

两种环境的配置在webpack4中都支持mode的配置:development/production,具体的默认配置查询可以移步这里:webpack4 Mode的默认设置 。

 const webpack = require("webpack");
 const path = require("path");
 const merge = require("webpack-merge");
//  const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
 const common = require("./webpack.common.js");


 module.exports = merge(common, {
     output:{
        // publicPath:path.resolve(__dirname, "dist"),
     },
     mode:"production",
 });

指定环境为生产环境,默认开启UglifyJSPlugin。

【扩展】将文件标记为无副作用(side-effect-free)
src/math.js:

export function square(x) {
  return x * x;
}

export function cube(x) {
  return x * x * x;
}

src/index.js:

import { cube } from "./math.js";

math.js文件的square函数没有被导入,但是,它仍然被包含在 bundle 中。
在一个纯粹的 ESM 模块世界中,识别出哪些文件有副作用很简单。然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。
这种方式是通过 package.json 的 "sideEffects" 属性来实现的。

{
  "name": "your-project",
  "sideEffects": false
}

如同上面提到的,如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack,它可以安全地删除未用到的 export 导出。
如果你的代码确实有一些副作用,那么可以改为提供一个数组:

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js"
  ]
}
三 后记

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95528.html

相关文章

  • Vue 2.0 开发聊天程序(一): 初建项目

    摘要:它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。安装和使用在之后的实践过程中讲解。有一套良好的代码规范,对于项目的开发和维护都很友好。 努力了,不一定能成功,但是不努力,感觉好舒服啊                   ——努训 没有了解过vue1.*,直接上手vue2.0;虽然有些吃力但还是很愉快了学下来了。 一丶环境配置 node.js...

    荆兆峰 评论0 收藏0
  • H5新人福音~零配置搭建代化前端工程

    摘要:它可以让你在没有任何构建工具例如或等工具配置经验的情况下,帮你快速生成一个完整的前端工程,并可以打包代码和静态资源,使你的项目以最优异的性能上线。针对痛点零配置,快速搭建繁琐的开发环境搭建。自适应解决方案实现多终端显示一致。 X-BUILD一套基于Webpack(v4.21.0)快速搭建H5场景开发环境的脚手架,只需要几分钟的时间就可以运行起来。X-BUILD是针对H5开发的一套自动化...

    GraphQuery 评论0 收藏0
  • 前端面试题(3)现代技术

    摘要:什么是单页面应用单页面应用是指用户在浏览器加载单一的页面,后续请求都无需再离开此页目标旨在用为用户提供了更接近本地移动或桌面应用程序的体验。流程第一次请求时,将导航页传输到客户端,其余请求通过获取数据实现数据的传输通过或远程过程调用。 什么是单页面应用(SPA)? 单页面应用(SPA)是指用户在浏览器加载单一的HTML页面,后续请求都无需再离开此页 目标:旨在用为用户提供了更接近本地...

    EasonTyler 评论0 收藏0

发表评论

0条评论

MyFaith

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<