在找一份相对完整的Webpack项目配置指南么?这里有

小说:利用旧电脑赚钱作者:陵成更新时间:2019-02-23字数:66054

在找一份相对完整的Webpack项目配置指南么?这里有


 

Webpack已经出来很久了,相关的文章也有很多,然而比较完整的例子却不是很多,让很多新手不知如何下脚,下脚了又遍地坑

说实话,官方文档是蛮乱的,而且有些还是错的错的。。很多配置问题只有爬过坑才知道

本文首先介绍Webpack的一些基础知识,然后以一个已经完成的小Demo,逐一介绍如何在项目中进行配置

该Demo主要包含编译Sass/ES6,提取(多个)CSS文件,提取公共文件,模块热更新替换,开发与线上环境区分,使用jQuery插件的方式、页面资源引入路径自动生成,编写一个简单的插件,异步加载模块 等基础功能

应该能帮助大家更好地在项目中使用Webpack3来管理前端资源

本文比较啰嗦,可以直接看第四部分Webpack3配置在Demo中的应用,或者直接去Fork这个Demo边看边玩

 

首先,学习Webpack,还是推荐去看官方文档,还是挺全面的,包括中文的和英文的,以及GitHub上关于webpack的项目issues,还有就是一些完整了例子,最后就是得自己练手配置,才能在过程中掌握好这枯燥的配置。

 

  • 1. 为什么要用Webpack
  • 2. 什么是Webpack
  • 3. Webpack的基础配置
    • 1. webpack的配置方式主要有三种
      • 1. 通过cli命令行传入参数
      • 2. 通过在一个配置文件设置相应配置,导出使用
      • 3. 通过使用NodeJS的API配置
    • 2. 常见的几个配置属性
      • 1. context  绝对路径
      • 2. entry  模块入口文件设置
      • 3. resolve 处理资源的查找引用方式
      • 4. output 设置文件的输出
      • 5. devtool指定sourceMap的配置
      • 6. module指定模块如何被加载
      • 7.  plugins设置webpack配置过程中所用到的插件
  • 4. Webpack3配置在Demo中的应用
    • 1. 搭建个服务器
    • 2. 设置基础项目目录
    • 3. 开发和生产环境的Webpack配置文件区分
    • 4. 设置公共模块
    • 5. 编译ES6成ES5
    • 6. 编译Sass成CSS,嵌入到页面<style>标签中,或将其提取出(多个)CSS文件来用<link>引入
    • 7. jQuery插件的引入方式 
    • 8. HtmlWebpackPlugin将页面模板编译成最终的页面文件,包含JS及CSS资源的引用
    • 9. 使用url-loader和file-loader和html-loader来处理图片、字体等文件的资源引入路径问题
    • 10. 模块热更新替换的正确姿势
    • 11. 压缩模块代码
    • 12. 异步加载模块
    • 13. 其他配置

 

一 、为什么要用Webpack

首先,得知道为什么要用webpack

前端本可以直接HTML、CSS、Javascript就上了,不过如果要处理文件依赖、文件合并压缩、资源管理、使用新技术改善生活的时候,就得利用工具来辅助了。

以往有常见的模块化工具RequireJS,SeaJS等,构建工具Grunt、Gulp等,新的技术Sass、React、ES6、Vue等,要在项目中使用这些东西,不用工具的话就略麻烦了。

其实简单地说要聚焦两点:模块化以及自动构建。

模块化可以使用RequireJS来处理依赖,使用Gulp来进行构建;也可以使用ES6新特性来处理模块化依赖,使用webpack来构建

两种方式都狠不错,但潮流所驱,后者变得愈来愈强大,当然也不是说后者就替代了前者,只是大部分情况下,后者更好

 

二、什么是Webpack

如其名,Web+Pack 即web的打包,主要用于web项目中打包资源进行自动构建。

Webpack将所有资源视为JS的模块来进行构建,所以对于CSS,Image等非JS类型的文件,Webpack会使用相应的加载器来加载成其可识别的JS模块资源

通过配置一些信息,就能将资源进行打包构建,更好地实现前端的工程化

 

三、Webpack的基础配置

可以认为Webpack的配置是4+n模式,四个基本的 entry(入口设置)output(输出设置)loader(加载器设置)、plugin(插件设置),然后加上一些特殊功能的配置。

使用Webpack首先需要安装好NodeJS

node -v
npm -v

确保已经可以使用node,使用NPM包管理工具来安装相应依赖包(网络环境差可以使用淘宝镜像CNPM来安装)

npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm -v

全局安装好webpack包

npm i -g webpack
webpack -v

 

1. webpack的配置方式主要有三种

1. 通过cli命令行传入参数 

webpack ./src.js -o ./dest.js --watch --color 

2. 通过在一个配置文件设置相应配置,导出使用

// ./webpack.config.js文件
module.exports = {
   context: ... entry: { }, output: { } };
// 命令行调用(不指定文件时默认查找webpack.config.js) webpack [--config webpack.config.js]

3. 通过使用NodeJS的API配置

这个和第二点有点类似,区别主要是第二种基本都是使用{key: value}的形式配置的,API则主要是一些调用

另外,某些插件的在这两种方式的配置上也有一些区别

 

最常用的是第二种,其次第三种,第一种不太建议单独使用(因为相对麻烦,功能相对简单)

 

2. 常见的几个配置属性

1. context  绝对路径

一般当做入口文件(包括但不限于JS、HTML模板等文件)的上下文位置,

默认使用当前目录,不过建议还是填上一个

// 上下文位置
context: path.resolve(__dirname, "static")

2. entry  模块入口文件设置

可以接受字符串表示一个入口文件,不过一般来说是多页应用多,就设置成每页一个入口文件得了

比如home对应于一个./src/js/home模块,这里的key会被设置成webpack的一个chunk,即最终webpack会又三个chunkname:home | detail | common

也可以对应于多个模块,用数组形式指定,比如这里把jquery设置在common的chunk中

也可以设置成匿名函数,用于动态添加的模块

// 文件入口配置
    entry: {
        home: "./src/js/home",
        detail: "./src/js/detail",
        // 提取jquery入公共文件
        common: ["jquery"]
    },

3. resolve 处理资源的查找引用方式

如上方其实是省略了后JS缀,又比如想在项目中引入util.js 可以省略后缀

import {showMsg} from "./components/util";
// 处理相关文件的检索及引用方式
    resolve: {
        extensions: [".js", ".jsx", ".json"],
        modules: ["node_modules"],
        alias: {

        }
    },

4. output 设置文件的输出

最基础的就是这三个了

path指定输出目录,要注意的是这个目录影响范围是比较大,与该chunk相关的资源生成路径是会基于这个路径的

filename指定生成的文件名,可以使用[name] [id]来指定相应chunk的名称,如上的home和detail,用[hash]来指定本次webpack编译的标记来防缓存,不过建议是使用[chunkhash]来依据每个chunk单独来设置,这样不改变的chunk就不会变了

hash放在?号之后的好处是,不会生成新的文件(只是文件内容被更改了),同时hash会附在引用该资源的URL后(如script标签中的引用)

publicPath指定所引用资源的目录,如在html中的引用方式,建议设置一个

 

// 文件输出配置
    output: {
        // 输出所在目录
        path: path.resolve(__dirname, "static/dist/js"),
        filename: "[name].js?[chunkhash:8]"// 设置文件引用主路径
        publicPath: "/public/static/dist/js/"
    }

5.devtool指定sourceMap的配置

如果开启了,就可以在浏览器开发者工具查看源文件

// 启用sourceMap
    devtool: "cheap-module-source-map",

比如这里就是对应的一个source Map,建议在开发环境下开启,帮助调试每个模块的代码

这个配置的选项是满多的,而且还可以各种组合,按照自己的选择来吧

6. module指定模块如何被加载

通过设置一些规则,使用相应的loader来加载

主要就是配置modulerules规则组,通过use字段指定loader,如果只有一个loader,可以直接用字符串,loader要设置options的就换成数组的方式吧

或者使用多个loader的时候,也用数组的形式,规则不要用{ }留空,在windows下虽然正常,但在Mac下会报错提示找不到loader

多个loader遵循从右到左的pipe 的方式,如下 eslint-loader是先于babel-loader执行的

通过excludeinclude等属性再确定规则的匹配位置

// 模块的处理配置,匹配规则对应文件,使用相应loader配置成可识别的模块
    module: {
        rules: [{
           test: /.css$/,
           use: "css-loader"
        }, {
            test: /.jsx?$/,
            // 编译js或jsx文件,使用babel-loader转换es6为es5
            exclude: /node_modules/,
            use: [{
                loader: "babel-loader",
                options: {

                }
            }, {
                loader: "eslint-loader"
            }]
        }

7.  plugins设置webpack配置过程中所用到的插件

比如下方为使用webpack自带的提取公共JS模块的插件

// 插件配置
    plugins: [
        // 提取公共模块文件
        new webpack.optimize.CommonsChunkPlugin({
            chunks: ["home", "detail"],
            filename: "[name].js",
            name: "common"
        }),
       new ...

]

这就是webpack最基础的东西了,看起来内容很少,当然还有其他很多,但复杂的地方在于如何真正去使用这些配置

 

四、Webpack配置在Demo中的应用

下面以一个相对完整的基础Demo着手,介绍一下几个基本功能该如何配置

Demo项目地址   建议拿来练练

 

1. 搭建个服务器

既然是Demo,至少就得有一个服务器,用node来搭建一个简单的服务器,处理各种资源的请求返回

新建一个服务器文件server.js,以及页面文件目录views,其他资源文件目录public

服务器文件很简单,请求什么就返回什么,外加了一个gzip的功能

let http = require("http"),
    fs = require("fs"),
    path = require("path"),
    url = require("url"),
    zlib = require("zlib");

http.createServer((req, res) => {
    let {pathname} = url.parse(req.url),
        acceptEncoding = req.headers["accept-encoding"] || "",
        referer = req.headers["Referer"] || "",
        raw;

    console.log("Request: ", req.url);

    try {
        raw = fs.createReadStream(path.resolve(__dirname, pathname.replace(/^//, "")));

        raw.on("error", (err) => {
            console.log(err);

            if (err.code === "ENOENT") {
                res.writeHeader(404, {"content-type": "text/html;charset="utf-8""});
                res.write("<h1>404错误</h1><p>你要找的页面不存在</p>");
                res.end();
            }
        });

        if (acceptEncoding.match(/gzip/)) {
            res.writeHead(200, { "Content-Encoding": "gzip" });
            raw.pipe(zlib.createGzip()).pipe(res);
        } else if (acceptEncoding.match(/deflate/)) {
            res.writeHead(200, { "Content-Encoding": "deflate" });
            raw.pipe(zlib.createDeflate()).pipe(res);
        } else {
            res.writeHead(200, {});
            raw.pipe(res);
        }
    } catch (e) {
        console.log(e);
    }
}).listen(8088);

console.log("服务器开启成功", "localhost:8088/");

2. 设置基础项目目录

页面文件假设采用每一类一个目录,目录下的tpl为源文件,另外一个为生成的目标页面文件

/public目录下,基本配置文件就放在根目录下,JS,CSS,Image等资源文件就放在/public/static目录下

我们要利用package.json文件来管理编译构建的包依赖,以及设置快捷的脚本启动方式,所以,先在/public目录下执行 npm init

public/static/dist目录用来放置编译后的文件目录,最终页面引用的将是这里的资源

public/static/imgs目录用来放置图片源文件,有些图片会生成到dist中

public/static/libs目录主要用来放置第三方文件,也包括那些很少改动的文件

public/static/src 用来放置js和css的源文件,相应根目录下暴露一个文件出来,公共文件放到相应子目录下(如js/componentsscss/util

 

最后文件结构看起来是这样的,那就可以开干了

 

 

3. 开发和生产环境的Webpack配置文件区分

首先在项目目录下安装webpack吧

npm i webpack --save-dev

用Webpack来构建,在开发环境和生产环境的配置还是有一些区别的,构建是耗时的,比如在开发环境下就不需要压缩文件、计算文件hash、提取css文件、清理文件目录这些辅助功能了,而可以引入热更新替换来加快开发时的模块更新效率。

所以建议区分一下两个环境,同时将两者的共同部分提取出来便于维护

NODE_ENV是nodejs在执行时的环境变量,webpack在运行构建期间也可以访问这个变量,所以我们可以在devprod下配置相应的环境变量

这个配置写在package.json里的scripts字段就好了,比如

"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build:dev": "export  NODE_ENV=development && webpack-dev-server --config webpack.config.dev.js",
    "build:prod": "export NODE_ENV=production && webpack --config webpack.config.prod.js --watch "
  },

这样一来,我们就可以直接用 npm run build:prod来执行生产环境的配置命令(设置了production的环境变量,使用prod.js)

直接用npm run build:dev来执行开发环境的配置命令(设置了development的环境变量,使用dev.js,这里还使用了devServer,后面说)

注意这里是Unix系统配置环境变量的写法,在windows下,记得改成 SET NODE_ENV=development&& webpack-dev-server.......(&&前不要空格)

 

然后就可以在common.js配置文件中获取环境变量

// 是否生产环境
    isProduction = process.env.NODE_ENV === "production",

然后可以在plugins中定义一个变量提供个编译中的模块文件使用

// 插件配置
    plugins: [
        // 定义变量,此处定义NODE_ENV环境变量,提供给生成的模块内部使用
        new webpack.DefinePlugin({
            "process.env": {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV)
            }
        }),

这样一来,我们可以在home.js中判断是否为开发环境来引入一些文件

// 开发环境时,引入页面文件,方便改变页面文件后及时模块热更新
if (process.env.NODE_ENV === "development") {
    require("../../../../views/home/home.html");
}

 

然后我们使用webpack-merge工具来合并公共配置文件和开发|生产配置文件

npm i webpack-merge --save-dev


merge = require("webpack-merge")

commonConfig = require("./webpack.config.common.js")


/**
 * 生产环境Webpack打包配置,整合公共部分
 * @type {[type]}
 */
module.exports = merge(commonConfig, {
    // 生产环境不开启sourceMap
    devtool: false,

    // 文件输出配置
    output: {
        // 设置文件引用主路径
        publicPath: "/public/static/dist/js/"
    },

    // 模块的处理配置

 

4. 设置公共模块

公共模块其实可以分为JS和CSS两部分(如果有提取CSS文件的话)

在公共文件的plugin中加入

// 提取公共模块文件
        new webpack.optimize.CommonsChunkPlugin({
            chunks: ["home", "detail"],
            // 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
            filename: "[name].js" + (isProduction ? "?[chunkhash:8]" : ""),
            name: "common"
        }),

设置公共文件的提取源模块chunks,以及最终的公共文件模块名

公共模块的文件的提取规则是chunks中的模块公共部分,如果没有公共的就不会提取,所以最好是在entry中就指定common模块初始包含的第三方模块,如jquery,react等

 // 文件入口配置
    entry: {
        home: "./src/js/home",
        detail: "./src/js/detail",
        // 提取jquery入公共文件
        common: ["jquery"]
    },

5. 编译ES6成ES5

要讲ES6转换为ES5,当然首用babel了,先安装loader及相关的包

npm i babel-core babel-loader babel-preset-env babel-polyfill babel-plugin-transform-runtime --save-dev

-env包主要用来配置语法支持度

-polyfill用来支持一些ES6拓展的但babel转换不了的方法(Array.from Generator等)

-runtime用来防止重复的ES6编译文件所需生成(可以减小文件大小)

然后在/public根目录下新建 .babelrc文件,写入配置

{
    "presets": [
        "env"
    ],
    "plugins": ["transform-runtime"]
}

然后在common.js的配置文件中新增一条loader配置就行了,注意使用exclude排除掉不需要转换的目录,否则可能会出错哦

{
            test: /.jsx?$/,
            // 编译js或jsx文件,使用babel-loader转换es6为es5
            exclude: /node_modules/,
            use: [{
                loader: "babel-loader",
                options: {

                }
            }]
        }

 

 6. 编译Sass成CSS,嵌入到页面<style>标签中,或将其提取出(多个)CSS文件来用<link>引入

sass的编译node-sass需要python2.7的环境,先确定已经安装并设置了环境变量

npm i sass-loader node-sass style-loader css-loader --save-dev

类似的,设置一下loader规则

不过这里要设置成使用提取CSS文件的插件设置了,因为它的disable属性可以快速切换是否提取CSS(这里设置成生产环境才提取)

好好看这个栗子,其实分三步:设置(new)两个实例,loader匹配css和sass两种文件规则,在插件中引入这两个实例

提取多个CSS文件其实是比较麻烦的,但也不是不可以,方法就是设置多个实例和对应的几个loader规则

这里把引入的sass当做是自己写的文件,提取成一个文件[name].css,把引入的css当做是第三方的文件,提取成一个[name]_vendor.css,既做到了合并,也做到了拆分,目前还没想到更好的方案

上面提到过,output的path设置成了/public/static/dist/js ,所以这里的filename 生成是基于上面的路径,可以用../来更换生成的css目录

[contenthash]是css文件内容的hash,在引用它的地方有体现

fallback表示不可提取时的代替方案,即上述所说的使用style-loader嵌入到<style>标签

npm i extract-text-webpack-plugin --save-dev


ExtractTextWebpackPlugin = require("extract-text-webpack-plugin")

/ 对import 引入css(如第三方css)的提取
    cssExtractor = new ExtractTextWebpackPlugin({
        // 开发环境下不需要提取,禁用
        disable: !isProduction,
        filename: "../css/[name]_vendor.css?[contenthash:8]",
        allChunks: true
    })

    // 对import 引入sass(如自己写的sass)的提取
    sassExtractor = new ExtractTextWebpackPlugin({
        // 开发环境下不需要提取,禁用
        disable: !isProduction,
        filename: "../css/[name].css?[contenthash:8]",
        allChunks: true
    });




// 插件配置
    plugins: [
        // 从模块中提取CSS文件的配置
        cssExtractor,
        sassExtractor
    ]


    



module: {
        rules: [{
            test: /.css$/,
            // 提取CSS文件
            use: cssExtractor.extract({
                // 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
                fallback: "style-loader",
                use: [{
                        loader: "css-loader",
                        options: {
                            // url: false,
                            minimize: true
                        }
                    },
                    // "postcss-loader"
                ]
            })
        }, {
            test: /.scss$/,
            // 编译Sass文件 提取CSS文件
            use: sassExtractor.extract({
                // 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
                fallback: "style-loader",
                use: [
                    "css-loader",
                    // "postcss-loader",
                    {
                        loader: "sass-loader",
                        options: {
                            sourceMap: true,
                            outputStyle: "compressed"
                        }
                    }
                ]
            })
        }

这样一来,如果在不同文件中引入不同的文件,生成的css可能长这样

// ./home.js
import "../../libs/bootstrap-datepicker/datepicker3.css";

import "../../libs/chosen/chosen.1.0.0.css";

import "../../libs/layer/skin/layer.css";

import "../../libs/font-awesome/css/font-awesome.min.css";


import "../scss/detail.scss";




// ./detail.js
import "../../libs/bootstrap-datepicker/datepicker3.css";

import "../../libs/chosen/chosen.1.0.0.css";

import "../../libs/layer/skin/layer.css";

import "../scss/detail.scss";

// ./home.html
<link href="/public/static/dist/js/../css/common_vendor.css?66cb1f48" rel="stylesheet">
<link href="/public/static/dist/js/../css/common.css?618d2a04" rel="stylesheet">
<link href="/public/static/dist/js/../css/home_vendor.css?12a314c8" rel="stylesheet">
<link href="/public/static/dist/js/../css/home.css?c196fc33" rel="stylesheet">




// ./detail.html
<link href="/public/static/dist/js/../css/common_vendor.css?66cb1f48" rel="stylesheet">
<link href="/public/static/dist/js/../css/common.css?618d2a04" rel="stylesheet">

可以看到,公共文件也被提取出来了,利用HtmlWebpackPlugin就能将其置入了

另外,可以看到这里的绝对路径,其实就是因为在output中设置了publicPath为/public/static/dist/js/

 

当然了,也不是说一定得在js中引入这些css资源文件,你可以直接在页面中手动<link>引入第三方CSS

我这里主要是基于模块化文件依赖,以及多CSS文件的合并压缩的考虑才用这种引入方式的

 

7. jQuery插件的引入方式 

 目前来说,jQuery及其插件在项目中还是很常用到的,那么就要考虑如何在Webpack中使用它

第一种方法,就是直接页面中<script>标签引入了,但这种方式不受模块化的管理,好像有些不妥

第二种方法,就是直接在模块中引入所需要的jQuery插件,而jQuery本身由Webpack插件提供,通过ProvidePlugin提供模块可使用的变量$|jQuery|window.jQuery

不过这种方法好像也有不妥,把所有第三方JS都引入了,可能会降低编译效率,生成的文件也可能比较臃肿

npm i jquery --save



// 
plugins: [
    new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
            "window.jQuery": "jquery"
        }),

]



// ./home.js


import "../../libs/bootstrap-datepicker/bootstrap-datepicker.js";
console.log(".header__img length", jQuery(".header__img").length);

第三种办法,可以在模块内部直接引入jQuery插件,也可以直接在页面通过<script>标签引入jQuery插件,而jQuery本身由Webpack的loader导出为全局可用

上述ProvidePlugin定义的变量只能在模块内部使用,我们可以使用expose-loader将jQuery设置为全局可见

npm i expose-loader --save



// 添加一条规则
{
            test: require.resolve("jquery"),
            // 将jQuery插件变量导出至全局,提供外部引用jQuery插件使用
            use: [{
                loader: "expose-loader",
                options: "$"
            }, {
                loader: "expose-loader",
                options: "jQuery"
            }]
        }

要注意在Webpack3中不能使用webpack.NamedModulesPlugin()来获取模块名字,它会导致expose 出错失效(bug)

 

不过现在问题又来了,这个应该是属于HtmlWebpackPlugin的不够机智的问题,先说说它怎么用吧

 

8. HtmlWebpackPlugin将页面模板编译成最终的页面文件,包含JS及CSS资源的引用

第一个重要的功能就是生成对资源的引入了,第二个就是帮助我们填入资源的chunkhash值防止浏览器缓存

这个在生产环境使用就行了,开发环境是不需要的

npm i html-webpack-plugin --save-dev


HtmlWebpackPlugin = require("html-webpack-plugin")


plugins: [

 // 设置编译文件页面文件资源模块的引入
        new HtmlWebpackPlugin({
            // 模版源文件
            template: "../../views/home/home_tpl.html",
            // 编译后的目标文件
            filename: "../../../../views/home/home.html",
            // 要处理的模块文件
            chunks: ["common", "home"],
            // 插入到<body>标签底部
            inject: true
        }),
        new HtmlWebpackPlugin({
            template: "../../views/detail/detail_tpl.html",
            filename: "../../../../views/detail/detail.html",
            chunks: ["common", "detail"],
            inject: true
        }),



]

使用方式是配置成插件的形式,想对多少个模板进行操作就设置多少个实例

注意template是基于context配置中的上下文的,filename是基于output中的path路径的

// ./home_tpl.html

    <script src="/public/static/libs/magicsearch/jquery.magicsearch2.js"></script>
</body>



// ./home.html

<script src=/public/static/libs/magicsearch/jquery.magicsearch2.js></script>
<script type="text/javascript" src="/public/static/dist/js/common.js?cc867232"></script>
<script type="text/javascript" src="/public/static/dist/js/home.js?5d4a7836"></script>
</body>

它会编译成这样,然而,然而,要注意到这里是有问题的

这里有个jQuery插件,而Webpack使用expose是将jQuery导出到了全局中,我们通过entry设置把jQuery提取到了公共文件common中

所以正确的做法是common.js文件先于jQuery插件加载

而这个插件只能做到在<head> 或<body>标签尾部插入,我们只好手动挪动一下<script>的位置

 

不过,我们还可以基于这个插件,再写一个插件来实现自动提升公共文件 <script>标签到最开始

HtmlWebpackPlugin运行时有一些事件

    html-webpack-plugin-before-html-generation
    html-webpack-plugin-before-html-processing
    html-webpack-plugin-alter-asset-tags
    html-webpack-plugin-after-html-processing
    html-webpack-plugin-after-emit
    html-webpack-plugin-alter-chunks

在编译完成时,正则匹配到<script>标签,找到所设置的公共模块(可能设置了多个公共模块),按实际顺序提升这些公共模块即可

完整代码如下:

 1 // ./webpack.myPlugin.js
 2 
 3 
 4 let extend = require("util")._extend;
 5 
 6 
 7 // HtmlWebpackPlugin 运行后调整公共script文件在html中的位置,主要用于jQuery插件的引入
 8 function HtmlOrderCommonScriptPlugin(options) {
 9     this.options = extend({
10         commonName: "common"
11     }, options);
12 }
13 
14 HtmlOrderCommonScriptPlugin.prototype.apply = function(compiler) {
15     compiler.plugin("compilation", compilation => {
16         compilation.plugin("html-webpack-plugin-after-html-processing", (htmlPluginData, callback) => {
17             // console.log(htmlPluginData.assets);
18 
19             // 组装数组,反转保证顺序
20             this.options.commonName = [].concat(this.options.commonName).reverse();
21 
22             let str = htmlPluginData.html,
23                 scripts = [],
24                 commonScript,
25                 commonIndex,
26                 commonJS;
27 
28             //获取编译后html的脚本标签,同时在原html中清除
29             str = str.replace(/(<script[^>]*>(s|S)*?</script>)/gi, ($, $1) => {
30                 scripts.push($1);
31                 return "";
32             });
33 
34             this.options.commonName.forEach(common => {
35                 if (htmlPluginData.assets.chunks[common]) {
36                     // 找到公共JS标签位置
37                     commonIndex = scripts.findIndex(item => {
38                         return item.includes(htmlPluginData.assets.chunks[common].entry);
39                     });
40 
41                     // 提升该公共JS标签至顶部
42                     if (commonIndex !== -1) {
43                         commonScript = scripts[commonIndex];
44                         scripts.splice(commonIndex, 1);
45                         scripts.unshift(commonScript);
46                     }
47                 }
48             });
49 
50             // 重新插入html中
51             htmlPluginData.html = str.replace("</body>", scripts.join("
") + "
</body>");
52 
53             callback(null, htmlPluginData);
54         });
55     });
56 };
57 
58 
59 module.exports = {
60     HtmlOrderCommonScriptPlugin,
61 };

 

然后,就可以在配置中通过插件引入了

{HtmlOrderCommonScriptPlugin} = require("./webpack.myPlugin.js");


// HtmlWebpackPlugin 运行后调整公共script文件在html中的位置,主要用于jQuery插件的引入
        new HtmlOrderCommonScriptPlugin({
            // commonName: "vendor"
        })

亲测还是蛮好用的,可以应对简单的需求了

 

9. 使用url-loader和file-loader和html-loader来处理图片、字体等文件的资源引入路径问题

这个配置开发环境和生产环境是不同的,先看看生产环境的,主要的特点是有目录结构的设置,设置了一些生成的路径以及名字信息

开发环境因为是使用了devServer,不需要控制目录结构

npm i url-loader file-loader@0.10.0 html-loader --save-dev

这里要注意的是file-loader就不要用0.10版本以上的了,会出现奇怪的bug,主要是下面设置的outputPath和publicPath和[path]会不按套路出牌

导致生成的页面引用资源变成奇怪的相对路径

rules: [{
            test: /.(png|gif|jpg)$/,
            use: {
                loader: "url-loader",
                // 处理图片,当大小在范围之内时,图片转换成Base64编码,否则将使用file-loader引入
                options: {
                    limit: 8192,
                    // 设置生成图片的路径名字信息 [path]相对context,outputPath输出的路径,publicPath相应引用的路径
                    name: "[path][name].[ext]?[hash:8]",
                    outputPath: "../",
                    publicPath: "/public/static/dist/",
                }
            }
        }, {
            test: /.(eot|svg|ttf|otf|woff|woff2)w*/,
            use: [{
                loader: "file-loader",
                options: {
                    // 设置生成字体文件的路径名字信息 [path]相对context,outputPath输出的路径,publicPath相应引用的主路径
                    name: "[path][name].[ext]?[hash:8]",
                    outputPath: "../",
                    publicPath: "/public/static/dist/",
                    // 使用文件的相对路径,这里先不用这种方式
                    // useRelativePath: isProduction
                }
            }],
        }, {
            test: /.html$/,
            // 处理html源文件,包括html中图片路径加载、监听html文件改变重新编译等
            use: [{
                loader: "html-loader",
                options: {
                    minimize: true,
                    removeComments: false,
                    collapseWhitespace: false

当前文章:http://adsl66.com/39855.html

发布时间:2019-02-23 00:13:03

最适合男性的第二职业的资源 天津微信兼职女 微投赚大钱原理 网络公司怎么赚钱 什么网站可以赚钱 学生在qq上怎么赚钱 手机赚钱一天赚十快 可以赚钱的网络游戏 微店代理订单谁发货 京东推广佣金比例

90520 17045 50488 87785 98767 5931247912 67233 61050

我要说两句: (0人参与)

发布