Node.js/webpack

来自康健生活
跳到导航 跳到搜索

引言

npm install -g webpack

webpack-cli

sudo npm install webpack-cli

命令行

[jian@kang /home/kangkk]$
webpack --config webpack.config.js
Hash: 167bbdb89a5dbf82c4d0
Version: webpack 4.43.0
Child
    Hash: 167bbdb89a5dbf82c4d0
    Time: 151ms
    Built at: 2020-06-28 10:07:55 ├F10: PM┤
                Asset      Size   Chunks                         Chunk Names
    index.167bbdb8.js  2.11 KiB  0, 1, 2  [emitted] [immutable]  index
     info.167bbdb8.js  2.11 KiB  1, 0, 2  [emitted] [immutable]  info
     list.167bbdb8.js  2.11 KiB  2, 0, 1  [emitted] [immutable]  list
    Entrypoint index = index.167bbdb8.js
    Entrypoint info = info.167bbdb8.js
    Entrypoint list = list.167bbdb8.js
    [0] ./public/js/index.js 3.74 KiB {0} {1} {2} [built]

externals

{
  externals:{
    'vue': 'Vue',
  },
}

先不说官方文档的解释,externals 这个配置项是将其所标注的组件直接挂在全局(也就是最上层作用域),以此减少业务代码的内部组件引用,从而减少代码打包量。其扩展,可用于 cdn 或者 dll 的应用。

router/index.js
...
import InfoMain from "@/info/Main.vue";
import ListMain from "@/list/Main.vue";
import Vuw from "vue";

export default new VueRouter({
...
...
import InfoMain from "@/info/Main.vue";
import ListMain from "@/list/Main.vue";


export default new VueRouter({
...

dll

js

当代码有多页面重复使用,类似于类库的组件想要单独提取出来使用,找到现在的方案 dll。新建配置文件如下:

webpack.dll.config.js
...
const devMode = process.env.NODE_ENV !== 'production' ? 'development' : 'production';
const dllPath = path.join(__dirname, 'public/dll');
module.exports = {
    ...
    plugins: [
       ...
        new webpack.DllPlugin({
            name: '_dll_[name]',
            path: path.join(__dirname, 'public/dll', 'manifest.json')
        }),
        ...
    ],
    optimization: {
        splitChunks: {
            cacheGroups: {
                elementStyles: {
                    ...
                },
                commonStyles: {
                    ...
                }
            }
        }
        ...
    }
}
webpack.config.js
...
new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./public/dll/manifest.json')
        }),
        new AddAssetHtmlPlugin([
        ...
    }
}

暂时遇到的问题是如果遇到 css 的类库,打包 [name].css 的同时会被一起生成 [name].js。时间问题,留待后续解决(css 被成功分离为什么还会生成 js 文件)

项目引入

不管是 cdn 还是 dll,配置 externals 之后就不需要在业务代码中继续引入这些组件了。如:

    /**
     * 不打包 vue.js, vue-router, element-ui 库
     */
    externals: {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'element-ui': 'ELEMENT',
        'axios': 'axios',
    },
router/index.js
const VueRouter = require('vue-router')
export default new VueRouter({
//
export default new VueRouter({

css

如果使用 dll 引用 css 组件,遇到的问题是会多出来一个 .css.js 的文件,如果使用 new FixStyleOnlyEntriesPlugin() 删除又会报错,所以这里的 css 组件不要用 new webpack.DllReferencePlugin() 方式引用,转为使用 new AddAssetHtmlPlugin() 是更好的选择。

/**
         * AddAssetHtmlPlugin
         * @description dll 组件插入 html 文档
         * @param publicPath 浏览器路径
         */
        new AddAssetHtmlPlugin([
            {
                filepath: path.resolve(__dirname, './public/dll/css/*.dll.min.css'),
                outputPath: 'dll',
                publicPath: path.posix.join('./', 'dll'),
                includeSourcemap: doDev,
                hash: true,
                typeOfAsset: 'css',
                /*attributes: {
                    nomodule: true,
                },*/
            },
        ]),

manifest

设置 dll 多个类库时需要注意生成的 manifest.json 名加标记进行区分,不然会发生重复写入一个 manifest.josn 发生 json 格式错误。

...
entry: {
  element_ui: ['./public/css/element.css'],
  public_style: ['./public/css/common.css']
},
...
new webpack.DllPlugin({
  name: '[name].dll.[ext]',
  path: path.join(__dirname, 'public/dll', '[name]-manifest.json')
}),

配置文件

webpack.config.js

module.exports={
  //入口文件的配置项
  entry:{},
  //出口文件的配置项
  output:{},
  //模块:例如解读CSS,图片如何转换,压缩
  module:{},
  //插件,用于生产模版和各项功能
  plugins:[],
  //配置webpack开发服务功能
  devServer:{}
}

示例

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
var serverConfig = {
  target: 'node',
  mode: 'production',
  //入口文件的配置项
  entry: {
    index: './public/js/index.js',
    info: './public/js/index.js',
    list: './public/js/index.js'
  },
  //出口文件的配置项
  output: {
    path: path.resolve(__dirname, 'public/dist/js'),
    filename: '[name].[hash:8].js'
  },
  //模块:例如解读CSS,图片如何转换,压缩
  module: {
    rules: [
    { loader: 'style-loader' },
    {
      loader: 'css-loader',
      options: {
        modules: true
      }
    },
    { test: /\.ts$/, use: 'ts-loader' },
    {
      test: /\.js$/,
      use: {
        loader: 'raw-loader'
      },
      exclude: '/node_modules/'
    },
    {
      test: /\.(js|jsx)$/,
      use: 'babel-loader'
    }
    ]
  },
  //插件,用于生产模版和各项功能
  plugins: [
  new webpack.optimize.UglifyJsPlugin(),
  new HtmlWebpackPlugin({template: './src/index.html'})
  ],
  //配置webpack开发服务功能
  devServer: {}
};
var clientConfig = {
  target: 'web', // <=== 默认是 'web',可省略
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.js'
  }
  //…
};
module.exports = [ serverConfig, clientConfig ];

ES6、7

[jian@kang /home/kangkk]$
npm i --save-dev babel-preset-env @babel/core babel-loader
webpack.config.js
{
  module: {
    rules: [
      {
        test: /\.js$/, // 值一个正则,符合这些正则的资源会用一个loade来处理
        use: {
          loader: 'babel-loader', // 使用bable-loader来处理
          options: {  // 指定参数
            presets: [
              ['babel-preset-env', {
                targets: {
                  browsers: ['> 1%', 'last 2 version'] //具体可以去babel-preset里面查看
                }
              }]
            ] // 指定哪些语法编译
          }
        },
        exclude: '/node_module/' // 排除在外
      }
    ]
  },
}

.babelrc

{
    "presets": [
        ["babel-preset-env", {
            "targets": {
                "browsers": ["> 1%", "last 2 version"]
            } 
        }] 
    ],
    "plugins": ["transform-runtime"]
}

组件

html-webpack-plugin SplitChunksPlugin HashedModuleIdsPlugin react-hot-loader add-asset-html-webpack-plugin extract-text-webpack-plugin webpack-dev-middleware
mini-css-extract-plugin autoprefixer babel-loader clean-webpack-plugin css-loader cssnano extract-loader
file-loader html-critical-webpack-plugin html-loader image-webpack-loader imagemin-loader imagemin-pngquant img-loader
node-sass optimize-css-assets-webpack-plugin postcss-loader postcss-pxtorem sass-loader style-loader ts-loader
uglifyjs-webpack-plugin underscore-template-loader url-loader vue-style-loader webpack-bundle-analyzer webpack-cli webpack-dev-server

babel-cli

npm install babel-cli -g

babel-preset-env

npm install babel-preset-env --save-dev

loader

loader 的执行顺序非常重要,还没有看源代码,但只从文档就可以看出来是借鉴了管道的思想,loader 插件是解析文件提取内容然后分词,所以如果执行顺序出现错误可能会导致文件在管道流通过程中某一部分为被解析,导致下一个管道的分词提取出现语法错误,从而报错。我这几天遇到的一个典型的类似错误就是 css 的 loader 执行顺序不对导致的 scss -> css 过程解析失败。

style-loader

将css-loader打包好的css代码以<style>标签的形式插入到html文件中。

属性:

attrs {Object} {} 添加自定义 attrs 到 style 标签
attrs: {
  id: 'foo'
}
transform {Function} false 转换/条件加载 CSS,通过传递转换/条件函数
transform: 'transform.js'
transform.js
// 这里只有一个参数,即css字符串
module.exports = function (css) {
    console.log(css)
    const transformed = css.replace(/}/g, 'box-sizing: border-box;\n}')
    return transformed
}
insertAt Object} bottom 给定位置处插入style标签
insertInto {String} 给定位置中插入style标签
sourceMap {Boolean} false 启用/禁用 Sourcemap
convertToAbsoluteUrls {Boolean} false 启用 source map 后,将相对 URL 转换为绝对 URL
useable {Object} {}
singleton {Boolean} true
hmr {Boolean} true
base {Number} true 设置模块 ID 基础 (DLLPlugin)

css-loader

vue-loader

{
  test: /\.vue$/,
  loader: 'vue-loader',
  options: {
    compilerOptions: {
      preserveWhitespace: false
    }
  }
}

合并/压缩JS

在入口处指名待合并打包的文件。大致分为三种写法,需要注意的是当使用 dll 方案的时候 entry 只接受数组方式的文件引入,也就是 entry:["./index.js","./info.js"] 这种形式。

entry:"./index.js"
//
entry:["./index.js","./info.js"]
//
entry:{
  index:["./index.js","./info.js"]
}

babel-minify-webpack-plugin

babel-minify-webpack-plugin 是 babel 推荐的压缩组件,使用 uglifyjs-webpack-plugin 组件会与 babelversion:7 有冲突(es2015version:6 与 babelversion:7),在处理 .vue 文件提取 js 代码压缩时解决起来非常麻烦,所以使用 babel-minify-webpack-plugin 也是一个非常好的选择。
未压缩效果:

Webpack js com 1

配置文件:

webpack.dll.config.js
const MinifyPlugin = require("babel-minify-webpack-plugin");
...
    plugins: [
        new MinifyPlugin({
            removeConsole: true,
            removeDebugger: true,
        }, {
            comments: false,
            sourceMap: false,
        }),
    ]
...

使用后效果:

Webpack js com 2

可以对比 uglifyjs-webpack-plugin 的效果:

webpack.dll.config.js
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
...
        minimizer: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    compress: {
                        drop_console: true,
                        drop_debugger: true,
                        pure_funcs: ['console.log']
                    },
                    mangle: false,
                },
                test: /\.js(\?.*)?$/i,  //测试匹配文件,
                cache: true,//缓冲
                sourceMap: false,//源码调试
                parallel: true,//多进程并行运行
                extractComments: false, //禁止构建注释
            }),
    ]
...
Webpack js com 3

uglifyjs-webpack-plugin

在处理非 .vue 文件时 uglifyjs-webpack-plugin 依然是非常好的选择

插入文档顺序

插入文档顺序很容易出错,比如 dll、cdn 和提取的 js 文件是三种方式插入,顺序不同会出现各种匪夷所思的错误,蓦然回首才知道引用出错。
比如我现在举例的 js 组成为五种:js 代码、 .vue 文件提取的 js 代码、webpack 提取的公共代码、cdn 引入的代码、dll 引入的代码。 插入方式如下:

webpack.config.js
const externalConfig = [
    {
        name: 'element-ui',
        scope: 'Element',
        js: 'https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/index.js',
        //css: 'https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/theme-chalk/index.css'
    },
];
...
  entry: {
        index: './public/js/main.js',
        index_page_script: ['./public/js/index.js'],
    },
...
new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./public/dll/axios-manifest.json')
        }),
...
new HtmlWebpackPlugin(getHtmlConfig('index.html', 'view/index.ejs', '出国看病信息服务平台-出境医', ['index_page_script', 'main_style'], externalConfig)),
...
{
                filepath: path.resolve(__dirname, './public/dll/js/!*.dll.min.js'),
                outputPath: 'dll',
                publicPath: path.posix.join('./', 'dll'),
                includeSourcemap: doDev,
                hash: true,
                typeOfAsset: 'js',
                /!*attributes: {
                    nomodule: true,
                },*!/
            }

插入后结构如下(此处没有引入第一种:直接写的 js 代码):

index.html
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.1/index.js"></script>
<script src="dll/axios.dll.min.js?40da5eda282e09878e84"></script>
<script src="dll/Vue.dll.min.js?b95e317d686ea2eae43b"></script>
<script src="./js/default~index~index_page_script.b0876e4a.chunk.min.js?b0876e4a5b920e21cd67"></script>
<script src="./js/index_page_script.b0876e4a.min.js?b0876e4a5b920e21cd67"></script>

可以看到文档中 js 的插入顺序 element-ui 在 vue 之前,这一定是会发生错误的。

合并CSS

npm install style-loader css-loader --save-dev
webpack.config.js
module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        { loader:"style-loader" },
        { loader:"css-loader" }
      ]
    }
  ]
}

extract-text-webpack-plugin

npm install --save-dev extract-text-webpack-plugin@next

mini-css-extract-plugin

mini-css-extract-plugin 在 webpack4 中代替 extract-text-webpack-plugin

optimize-css-assets-webpack-plugin

uglifyjs-webpack-plugin

UglifyJS Webpack Plugin插件用来缩小(压缩优化)js文件,至少需要Node v6.9.0和Webpack v4.0.0版本。

webpack 4之前的版本是通过webpack.optimize.CommonsChunkPlugin来压缩js,webpack 4版本之后被移除了,使用config.optimization.splitChunks来代替。

图片

图片提取和压缩,还有小于设定值则转换为 base64 代码实现比较简单,如下:

{
  test: /\.(jpe?g|png|gif|svg)/,
  use: [
    {
      loader: 'url-loader',//给图片资源配置路径加载器,用于文件抽离
      options: {
        name: '[name][hash:5].[ext]',//设置抽离打包图片的名称--[ext]用来获取图片的后缀
        limit: 100000,//限制图片大小 <= 100kb 进行base64编码(小于100kb打包进js文件)--测试时根据图片的大小调整
        outputPath: 'imgs',//设置输出文件夹名称,这个文件夹会与主入口文件在同一路径下
        publicPath: '../imgs',
      }
    },
    {
      loader: 'img-loader',//配置图片资源加载器,用于图片压缩
      options: {
        plugins: [//给图片资源加载配置插件
          require('imagemin-pngquant')({//用于图片压缩的imagemin-pngquant,还有一个隐式调用的加载器imagemin-loader
            quality: [0.3, 0.5]//图片压缩30%~50%
          })
        ]
      }
    }
  ]
}

其中还使用了 img-loader 对图片进行处理。

postcss

  • autoprefixer是PostCSS最著名的一款插件,就不过多介绍了,相信同学们都使用过。
  • postcss-cssnext (内置autoprefixer) 允许你使用未来的css语法,如css4(可以理解为css中的Babel)
  • postcss-sprites 自动制作雪碧图,不用手动拼接啦,哈哈哈
  • cssnano 压缩css代码(如果你是用webpack的话,css-loader集成了cssnano,你不需要再次引入)
  • postcss-hash-classname 把转换后的css文件名附上哈希值
  • pixrem 将rem转换为px
  • postcss-px-to-viewport 将px转换为vh和vw(推荐作为移动端的计量单位,而不是rem)
  • postcss-pxtorem 将px转换为rem

webpack-bundle-analyzer

commonJS、AMD

require(["./module3"], function(){
    console.log("Hello Webpack!");
});
// 使用的是CommonJs机制导出包
module.exports = function(a, b){
    return a + b;
}
// 使用AMD模块机制
define(['./module2.js'], function(sum){
    return console.log("1 + 2 = " + sum(1, 2));
});
// 入口文件
require("./module1");

(来源摘自互联网示例,作者 博客园-二婷啵)

devtool

quality

Source Map

一般与下列类型的预处理器搭配使用:

  • 转译器(Babel)
  • 编译器(TypeScript)
  • Minifiers(UglifyJS)

硬编码

libraryTarget

webpack-dev-server

HMR(Hot Module Replacement)

遇到一个问题,前端页面在热更新的时候并不能显示出来,而是读取了原来目标文件夹并没有读取内存。

kangjian@kangkk:~/wk/chuyijing$
npm run hot
> chuyijing@1.0.0 hot /home/kangjian/wk/chuyijing
> webpack-dev-server --mode development --config webpack.config.js

10% [0] building 7/7 modules 0 activeℹ wds: Project is running at http://0.0.0.0:8000/
 wds: webpack output is served from /./
 wds: Content not from webpack is served from /home/kangjian/wk/chuyijing
 wds: 404s will fallback to /index.html
 wdm: Hash: 56a33961766f57c1e8b8
...

/webpack-dev-server

因为找不到页面,根据官方文档跳转到 http://localhost:8000/webpack-dev-server,查看生成文件路径。

imgs
  banner7bc56.jpg
js
  commons.js
  commons (magic html for commons.js) (webpack-dev-server)
  index.js
  index (magic html for index.js) (webpack-dev-server)
  info.js
  info (magic html for info.js) (webpack-dev-server)
  list.js
  list (magic html for list.js) (webpack-dev-server)
  main.js
  main (magic html for main.js) (webpack-dev-server)
  maincss.js
  maincss (magic html for maincss.js) (webpack-dev-server)
  vendor.js
  vendor (magic html for vendor.js) (webpack-dev-server)
  commons.js.map
  index.js.map
  info.js.map
  list.js.map
  main.js.map
  maincss.js.map
  vendor.js.map
css
  maincss.css
  maincss.css.map
  commoncss.css
  elementcss.css
index.html

遇到的问题是虽然能看到文件路径,但是依然打不开

kangjian@kangkk:~/wk/chuyijing$
curl http://localhost:8000/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /index.html</pre>
</body>
</html>

期间试着用关闭 new CleanWebpackPlugin({dry: doDev}) 的方法,让热更新的静态地址与服务器地址保持一致,可以打开页面并有数据,但是更改文件却并没有热更新,观察 cli。

...
       58 modules
    Child HtmlWebpackCompiler:
         1 asset
        Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
        [./node_modules/html-loader/dist/cjs.js!./view/common.html] 73 bytes {HtmlWebpackPlugin_0} [built]
            + 26 hidden modules
ℹ 「wdm」: Compiled successfully.

文件已经被重新编译,但是编译后的文件存放在内存中,并没有在与服务器根目录保持一致的静态地址。目前暂时没有解决的办法。

迫不得已用最简单的方式 writeToDisk: true,,将文件写入硬盘。

其他

内存溢出

  • 关掉 devtool

验证

  • 使用nodemon --inspect配合Chrome的inspect工具,进行内存快照
  • Allocation instrumentation on timeline

eval

打包到自执行函数体。这里遇到的问题是当我使用 elementUI 类库的时候,打包本地文件会被包装转化成 eval。当 elementUI 插入 html 文档后,刷新浏览器 elementUI 内置函数在 console 均可使用,但是页面样式没有改变,并且 ele 开头的标签没有转化为 html 标签。

试使用 立即执行函数体包裹 elementUI 进行重新打包。

(function(){
  // elementUI
})()

依然无效(google 之后相同问题很少,暂时没有时间具体解决,留待考证) 。暂时使用 cdn 方式曲线解决。

CDN

html 模板

ejs

在 html 中使用 ejs 语法大多数均可正常,但如 <% include ./index/head.html %> 会导致 html-webpack-plugin 解析错误(时间问题,报错原理未知,留待解决)

[jian@kang /home/kangkk]$
npm run dev
...
    Child HtmlWebpackCompiler:
         1 asset
        Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
        [./node_modules/html-webpack-plugin/lib/loader.js!./view/index.html] 756 bytes {HtmlWebpackPlugin_0} [built] [failed] [1 error]
        
        ERROR in ./view/index.html (./node_modules/html-webpack-plugin/lib/loader.js!./view/index.html)
        Module build failed (from ./node_modules/html-webpack-plugin/lib/loader.js):
        SyntaxError: Unexpected token '/'
            at Function (<anonymous>)
            at /home/kangjian/wk/chuyijing/node_modules/lodash/lodash.js:14870:16
            at apply (/home/kangjian/wk/chuyijing/node_modules/lodash/lodash.js:473:27)
            at /home/kangjian/wk/chuyijing/node_modules/lodash/lodash.js:15254:16
            at apply (/home/kangjian/wk/chuyijing/node_modules/lodash/lodash.js:475:27)
            at /home/kangjian/wk/chuyijing/node_modules/lodash/lodash.js:6563:16
            at Function.template (/home/kangjian/wk/chuyijing/node_modules/lodash/lodash.js:14869:20)
            at Object.module.exports (/home/kangjian/wk/chuyijing/node_modules/html-webpack-plugin/lib/loader.js:26:22)
...

这种情况可以使用 html-loader 解决,<%= require('html-loader!./index/head.html') %> 但同时会遇到新的问题,因为文件解析过程 html-loader 在 html-webpack-plugin 之后,而 html-loader 并不具备 ejs 模板解析功能,所以页面显示

[jian@kang /home/kangkk]$
curl localhost:8000
<!doctype html><html lang=en><head><meta charset=utf-8> <% htmlWebpackPlugin.options.cdnConfig.forEach(function(item){ if(item.css){ %> <link href="<%= item.css %>" rel=stylesheet> <% }}) %> <link href=css/elementcss.css?7894c68885238a09ba0c rel=stylesheet>

解决办法 ejs-html-loader

ejs-html-loader

{
  test:/\.html$/,
  loader: 'ejs-html-loader', // 使用 ejs-html-loader 处理 .ejs 文件的 includes 语法
  options: {
    production: doDev
  }
}

这里又遇到新的问题

[jian@kang /home/kangkk]$
npm run dev
...
    ERROR in   Error: Child compilation failed:
      Module Error (from ./node_modules/ejs-html-loader/lib/index.js):
      (Emitted value instead of an instance of Error) ejs-html-loader
      /home/kangjian/wk/chuyijing/view/index.html:3
          1| <!doctype html> 
          2| <html lang="en"> 
       >> 3| <%= require('html-loader!./index/head.html') %> 
          4| <body>
...

引入了 ejs-html-loader 之后,require 函数失效,依然与现有的组件冲突,不是说不好用,是冲突。

ejs-loader

诸般错误回头看,解决问题的办法就在最初。设置参数如下:

{
  test: /\.html$/,
  use: {
    loader: 'ejs-loader',
    options: {
      variable: 'data',
      interpolate : '\\{\\{\\{(.+?)\\}\\}\\}',
      evaluate : '\\[\\[\\[(.+?)\\]\\]\\]'
    }
  }
},

需要注意 interpolate 与 evaluate 的设定一定要和现有的模板语法不重叠,以免发生冲突。

ejs-compiled-loader

引入其他模块,这个是最终解决办法。

webpack.config.js
{
  loader: 'ejs-compiled-loader?'
},
index.ejs
<%- include index/header.ejs -%>

搜寻解决办法过程中,有人说搭配 underscore-template-loader 使用效果更加,但实测 underscore-template-loader 会破坏图片引用压缩处理的过程,通过替换解析标签发现无效,所以弃置。

现在的问题是,嵌套进来的文件因为不在 webpack 入口文件列表里,所以没有被监听。更新嵌套 ejs 的时候并不会更新 html 视图。

html-webpack-plugin

html-webpack-plugin 与 html-loader 解析冲突没有办法解决,如果一定要合并使用,只能将 html-webpack-plugin 的输入文件格式设定为 ejs,输出文件格式为 html,html-loader 寻找 html格式文件再进行解析。

...
{
  test:/\.html$/,
  use:[
    {
      loader:'html-loader',
      options:{
        attrs:['img:src']//配置html文件中img标签的src属性值
      }
    }
  ]
}
...
new HtmlWebpackPlugin(getHtmlConfig('index.html','view/index.ejs','首页',['main', 'maincss'],externalConfig)),
...

如果全局部署了 html 加载器将不解析 <% %>

sideEffects

sideEffects 试用了以下觉得问题很大,不是 sideEffects 不好,而是 sideEffects 的灵活度有点高,如果不是吃透 sideEffects 原理,尽量别用,之前使用的时候导致生产环境提取 .vue 文件内部 css 失败(开发环境正常),原理还不清除。此处标记,留待更新。

ERROR

  • ReferenceError: _dirname is not defined
    打包依赖错误,可以使用 cdn 加载方式避免,也可以用 dll 方式避免
  • FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
  • Module build failed: ReferenceError: document is not defined
    错误发生在打包 scss,style-loader、css-loader、sass-loader 等的执行顺序错误,正确的顺序是 style-loader -> MiniCssExtractPlugin.loader -> css-loader -> postcss-loader -> sass-loader
  • Module parse failed: Unexpected character '�' (1:0)
    遇到这个问题是没有安装 file-loader、url-loader
  • html-loader 与 html-webpack-plugin 的解析冲突问题
    无解。如果有特定需求比如将 html 文档中的 img 标签的引用图片一起打包,只能设置两个 webpack 配置文件顺序执行。如果只是使用模板语法可以单独在文件里引用 html-loader 标签,如 <%= require('html-loader!./common.html') %>
  • TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
    原因是在 babel-loader 组件中使用了 useBuiltIns: 'usage',解决办法非常简单,就是在 module.rules.exclude 中将 css、scss 等不想被遍历的文件或文件夹排除过滤掉,由于新版 webpack 的 exclude 规则不再支持 string、array,以至于一个小时后才找到问题所在,新版使用正则进行过滤 exclude: /((sc|sa|le|c)ss\/.*)|(node_modules\/.*)/
  • Uncaught ReferenceError: _dll_commoncss is not defined
  • 热启动时 css 类名中符合 BEM 规则的标签被删除
    原因是 sass-loader 组件的选项 options.sassOptions.outputStyle:'compressed' 开启了压缩,破坏了文档结构,关闭压缩即可,这个问题我排查了8个小时。
  • 热启动时报错 external "public_style_library":1 Uncaught ReferenceError: public_style_library is not defined
    public_style_library 引起的错误的连锁反应,AddAssetHtmlPlugin 组件插入 html 文档的顺序在 HtmlWebpackPlugin 引入组件之前,导致 js 加载顺序出现错误
  • 不稳定压缩优化
    在开启多个压缩优化后,会出现不稳定,举例:
    // 第一次构建生成结果
    .kk_dd--f {
        color: #3a8ee6
    }
    .banner .el-menu .el-submenu__title img {
        float: left;
        margin-top: 20px
    }
    // 第二次构建生成结果
    .kk--f, .kk_dd--f, .kk_ddf {
        color: #3a8ee6
    }
    .banner .el-menu .el-submenu__title img {
        float: left;
        margin-top: 20px
    }
    
  • html-webpack-plugin/lib/loader.js!/home/kangjian/github/vue-webpack/view/index.vue" didn't return html.
    vue-loader 不具备转换为 html 文档的能力,所以需要在 vue-loader 执行流后面加 html-loader
  • [VueLoaderPlugin Error] No matching use for vue-loader is found.
  • SassError: Invalid CSS after "a{}": expected 1 selector or at-rule, was "{}
    需要标记使用 sass 处理 css
    <style lang="scss" rel="stylesheet/scss" scoped>
    ...
    }
    
    继续报错 SassError: Invalid CSS after "a{}": expected 1 selector or at-rule, was "{},仔细看官方文档,sass 与 scss 的配置区别,发现如下已经被注释掉的部分引起。
    {
      /**
      * sass-loader
      * @description 解析 scss
      * @param outputStyle {string} 'compressed' 压缩
      * @param indentedSyntax {boolean} 缩进的sass语法
      */
      loader: 'sass-loader',
      options: {
        sourceMap: doDev,
        sassOptions: {
          outputStyle: false,
          // indentedSyntax: true
        },
      },
    },
    
  • Entrypoint mini-css-extract-plugin = *
  • 2 hidden modules
  • vue 提取 css 失败,用排除法,找到原因:package.json 中的 sideEffects,删除即可
  • UnhandledPromiseRejectionWarning: Error: Failed to launch chrome!
    (node:51153) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    Error: Failed to launch chrome!
    /root/vue-webpack/node_modules/puppeteer/.local-chromium/linux-637110/chrome-linux/chrome: error while loading shared libraries: libX11.so.6: cannot open shared object file: No such file or directory
    TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
        at onClose (/root/vue-webpack/node_modules/puppeteer/lib/Launcher.js:342:14)
    
    headless:false参数,Linux服务器没有图形界面没有办法运行。
  • ERROR: Failed to download Chromium r637110! Set "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" env variable to skip download.

Error: connect ECONNREFUSED 127.0.0.1:80

  • npm config set puppeteer_download_host=https://npm.taobao.org/mirrors
    npm i puppeteer
    
  • puppeteer和headless chrome依赖缺失
    [jian@kang /home/kangkk]$
    #依赖库
    yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y
    #字体
    yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
    
  • ERROR in js/index_page_script.405966ba.min.js from UglifyJs undefined
    打包vue文件时没有成功转换ES6的语法,webpack4 不推荐使用 UglifyJs,因为 preset-env-2015 模块版本与 babel7 不兼容,转为使用 babel-minify-webpack-plugin
  • Error: Plugin/Preset files are not allowed to export objects, only functions.
    package.json 依赖包中既有 babel 7.0 版本,又有 babel 6.0 版本,两个版本不兼容
  • 破坏 vue 里面的 css 提取,PurgecssPlugin 插件冲突
    只能删除 PurgecssPlugin
  • (node:167734) UnhandledPromiseRejectionWarning: Error: EACCES: permission denied, mkdir '/node_modules'
    使用了绝对路径,应该用相对路径或者项目内的绝对路径
            new HardSourceWebpackPlugin({
                cacheDirectory: './node_modules/.cache/hard-source/[confighash]',
                recordsPath: './node_modules/.cache/hard-source/[confighash]/records.json',
    
  • Maximum call stack size exceeded
  • Uncaught ReferenceError: ELEMENT is not defined
    配置文件里面映射出错
    externals: {
            'vue': 'Vue',
            'vue-router': 'VueRouter',
            'element-ui': 'ELEMENT',
        },
    
  • Uncaught ReferenceError: public_style_5e7f3e0efa8539219989 is not defined
  • element-ui 组件 Uncaught TypeError: Cannot read property 'prototype' of undefined
    组件引入顺序问题,element-ui 应该在 vue 下面
  • vue.min.js:6 TypeError: axios__WEBPACK_IMPORTED_MODULE_0___default.a.get is not a function
    这里是在使用 cdn 或者 dll 的情况下,业务代码中使用了 import 的错误,应该改为 requrie 或者直接省略不写。
  • axios.get 错误。
    当 vue、element-ui、vue-router 是 cdn 引入的时候,axios 为本地打包的 dll,会出现这种错误。缘由很醒目,是 axios 的打包方式有错误,但到底是哪里出错导致问题还没有排查出来。
  • Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
    在 webpack 打包的时候,可以在 js 文件中混用 require 和 export。但是不能混用 import 以及 module.exports