精华内容
下载资源
问答
  • Webpack 迁移到V4版本指南 需要升级的npm库列表 "webpack": "^4.6.0", "webpack-cli": "^2.0.15", "webpack-dev-middleware": "^3.1.2", "webpack-hot-middleware": "^2.22.1", "file-loader": "^1....
        

    Webpack 迁移到V4版本指南

    需要升级的npm库列表

    • "webpack": "^4.6.0",
    • "webpack-cli": "^2.0.15",
    • "webpack-dev-middleware": "^3.1.2",
    • "webpack-hot-middleware": "^2.22.1",
    • "file-loader": "^1.1.11",
    • "url-loader": "^1.0.1",
    • "html-webpack-plugin": "^3.2.0",
    • "less": "^3.0.4",
    • "less-loader": "^4.1.0",

    webpack.config.js 调整

    module 配置调整

    module.loaders 变成 module.rules

    module: {
        loaders: [
          {
            test: /\.css$/,
            loader: 'style!css',
          },
        ]
    }
    
    // change
    // 注意新版本的loader不能省略,即:style-loader 不能写成 style
    module: {
        rules: [
          {
            test: /\.css$/,
            use: [
              {loader: "style-loader"]},
              {loader: "css-loader"]},
            ]
          },
        ]
    }

    plugins 配置调整

    • remove extract-text-webpack-plugin
    • remove NoErrorsPlugin
    • remove UglifyJsPlugin
    • remove DedupePlugin
    • remove NamedModulesPlugin
    • remove HashedModulesPlugin
    • rename webpack.optimize.OccurenceOrderPlugin to webpack.optimize.OccurrenceOrderPlugin
    • remove CommonsChunkPlugin 改用 optimization.runtimeChuck 和 optimization.splitChunks

      onfig.optimization = {
        minimize: true,
        // runtimeChunk: 'single', // 测试发现这个设置成true或者single首页空白,无任何报错,因此暂时不做设置。
        splitChunks: {
          chunks: 'all',
          minSize: 30000,
          minChunks: 1,
          maxAsyncRequests: 5,
          maxInitialRequests: 3,
          automaticNameDelimiter: '~',
          name: true,
          cacheGroups: {
            vendors: {
              name: 'vendors',
              test: /[\\/]node_modules[\\/]/,
              priority: -10,
            },
            default: {
              minChunks: 2,
              priority: -20,
              reuseExistingChunk: true,
            },
          },
        },
      };

    添加 mode

    • 开发环境添加

      module.exports = {
        mode: 'development'
      }
    • 生产环境

      module.exports = {
        mode: 'production'
      }

    Code Spliting

    Q&A

    • Error: Cannot find module 'webpack/lib/ConcatSource'

      解决办法,移除:extract-text-webpack-plugin插件。(这里需要考虑如何抽离CSS)

    • OccurenceOrderPlugin has been renamed to OccurrenceOrderPlugin

      解决办法,修改 OccurenceOrderPlugin 成 OccurrenceOrderPlugin

    • ERROR in ./assets/images/icons/search.svg

      详细报错信息如下:

      ERROR in ./assets/images/icons/search.svg
      Module build failed: TypeError: Cannot read property 'context' of undefined
          at Object.loader (/Users/drew/Sites/my-site/node_modules/file-loader/dist/index.js:34:49)
      @ ./styles.sass 6:40863-40906

      解决办法:升级 url-loaderfile-loader

    • Cannot read property 'lessLoader' of undefined

      详细报错信息如下:

      ERROR in ./src/views/antdemo.less
      Module build failed: ModuleBuildError: Module build failed: TypeError: Cannot read property 'lessLoader' of undefined
          at Object.module.exports (/Users/gxz/workspace_js/react-demo/node_modules/less-loader/index.js:50:18)
          at runLoaders (/Users/gxz/workspace_js/react-demo/node_modules/webpack/lib/NormalModule.js:244:20)
          at /Users/gxz/workspace_js/react-demo/node_modules/loader-runner/lib/LoaderRunner.js:364:11
          at /Users/gxz/workspace_js/react-demo/node_modules/loader-runner/lib/LoaderRunner.js:230:18
          at runSyncOrAsync (/Users/gxz/workspace_js/react-demo/node_modules/loader-runner/lib/LoaderRunner.js:143:3)
          at iterateNormalLoaders (/Users/gxz/workspace_js/react-demo/node_modules/loader-runner/lib/LoaderRunner.js:229:2)
          at Array.<anonymous> (/Users/gxz/workspace_js/react-demo/node_modules/loader-runner/lib/LoaderRunner.js:202:4)
          at Storage.finished (/Users/gxz/workspace_js/react-demo/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:43:16)
          at provider (/Users/gxz/workspace_js/react-demo/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:79:9)
          at /Users/gxz/workspace_js/react-demo/node_modules/graceful-fs/graceful-fs.js:78:16
          at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:532:3)
      @ ./src/views/antddemo.js 44:0-25
      @ ./src/routes/antd.js
      @ ./src/routes/index.js

      解决办法:升级 lessless-loader

    展开全文
  • webpack 4迁移指南

    2019-04-26 08:33:40
    webpack 4 出来也已经一年了,公司的老项目用的还是webpack3,也是时候该升级一波了。...迁移的坑 CommonsChunkPlugin 废除, webpack 4内置了optimization.splitChunks 和 runtimeChunk 进行代码拆分 Extra...

    webpack 4 出来也已经一年了,公司的老项目用的还是webpack3,也是时候该升级一波了。说实话webpack4还是有几点挺吸引我的,估计也是感受到了parcel的压力,4这个版本内置了很多默认配置。

    迁移的坑

    1. CommonsChunkPlugin 废除, webpack 4内置了optimization.splitChunks 和 runtimeChunk 进行代码拆分
    2. ExtractTextPlugin 不支持webpack4,官方推荐了一个MiniCssExtractPlugin来拆分chunk中的css代码
    3. vue-loader 的升级,vue-loader 版本由14 升级到了15, 之前的配置也改变了具体参考从 v14 迁移

    基础配置

    const package = require('../package.json');
    const path = require('path');
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    const utils = require('./utils');
    
    function resolve (dir) {
        return path.join(__dirname, dir);
    }
    
    module.exports = {
        entry: {
            main: '@/main',
            'vender-exten': '@/vendors/vendors.exten.js'
        },
        output: {
            path: path.resolve(__dirname, '../dist/' + package.version) // 输出文件的绝对路径
        },
        module: {
            rules: [
                {
                    test: /\.(js|vue)$/,
                    loader: 'eslint-loader',
                    enforce: 'pre',
                    exclude: /node_modules/,
                    options: {
                        emitError: true,
                        emitWarning: false,
                        failOnError: true
                    }
                },
                {
                    test: /\.vue$/,
                    exclude: /node_modules/,
                    loader: 'vue-loader'
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader'
                    }
                },
                {
                    test: /\.js[x]?$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader'
                    }
                },
                {
                    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                    use: {
                        loader: 'url-loader',
                        options: {
                            limit: 10000,
                            name: utils.assetsPath('img/[name].[hash:7].[ext]')
                        }
                    }
                },
                {
                    test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
                    use: {
                        loader: 'url-loader',
                        options: {
                            limit: 10000,
                            name: utils.assetsPath('media/[name].[hash:7].[ext]')
                        }
                    }
                },
                {
                    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                    use: {
                        loader: 'url-loader',
                        options: {
                            limit: 10000,
                            name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
                        }
                    }
                }
            ]
        },
        plugins: [
            new VueLoaderPlugin(),
        ],
        resolve: {
            extensions: ['.js', '.vue'],
            alias: {
                '@': resolve('../src')
            }
        },
        externals: {
            AMap: 'AMap',
            vue: 'Vue',
            iview: 'iview',
            'vue-router': 'VueRouter',
            vuex: 'Vuex'
        }
    };
    复制代码

    如上,实现了对vue,jsx, js, 和资源文件对处理和转译

    开发环境配置

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const merge = require("webpack-merge");
    const webpackBaseConfig = require("./webpack.base.config.js");
    const config = require("./config");
    const webpack = require("webpack");
    
    
    module.exports = merge(webpackBaseConfig, {
        mode: 'development',
        devtool: '#source-map',
        output: {
            publicPath: '/dist/',
            filename: '[name].js',
            chunkFilename: '[name].chunk.js'
        },
        plugins: [
            new HtmlWebpackPlugin({
                title: 'admin management',
                filename: '../index.html',
                inject: false
            }),
        ],
    
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ['vue-style-loader', 'css-loader', 'postcss-loader']
                },
                {
                    test: /\.less$/,
                    use: [
                        'vue-style-loader',
                        'css-loader',
                        'postcss-loader',
                        'less-loader'
                    ]
                }
            ]
        },
    
        //设置跨域代理
        devServer: {
            public: 'local.xxxx.net:9000',
            port: 9000,
            proxy: {
                '/login': {
                    target: config.devApi.passport, 
                    pathRewrite: { '^/login': '/login' },
                    changeOrigin: true
                },
                '/v3': {
                    target: config.devApi.sass,
                    pathRewrite: { '^/v3': '/v3' },
                    changeOrigin: true
                }
            }
        }
    });
    复制代码

    如上,配置了开发环境的配置,注意webpack4多了一个mode,mode有三个选项可以选择:development, production, 和none,

    可以看官方的这个图,webpack会根据mode自动开启内置插件

    生产环境配置

    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const TerserJSPlugin = require('terser-webpack-plugin');
    const webpack = require('webpack')
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    const cleanWebpackPlugin = require('clean-webpack-plugin')
    const merge = require('webpack-merge')
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    const webpackBaseConfig = require('./webpack.base.config.js')
    const path = require('path')
    const package = require('../package.json')
    
    module.exports = merge(webpackBaseConfig, {
        mode: 'production', 
        output: {
            publicPath: '/' + package.version + '/', // 所有引入的文件资源都加上publicPath路径
            filename: '[name].[contenthash].js', // 输出 bundle 的名称, 入口(non-entry)
            chunkFilename: '[name].[contenthash].chunk.js' // 非入口(non-entry) chunk 文件的名称
        },
        optimization: {
            splitChunks: {
                cacheGroups: {
                    // 缓存组
                    commons: {
                        test: /[\\/]node_modules[\\/]/, // 只抽取引入的node_modules文件
                        name: 'vender-exten', // 要缓存的 分隔出来的 chunk 名称
                        chunks: 'all' // 对所有的chunk都进行缓存
                    }
                }
            },
            runtimeChunk: {
                name: 'runtime'
            }, 
            minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})]
        },
        module: {
            rules: [
                {
                    test: /\.css?$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'postcss-loader'
                    ]
                },
                {
                    test: /\.less$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'postcss-loader',
                        'less-loader'
                    ]
                }
            ]
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: '[name].[contenthash].css',
                chunkFilename: '[name].[contenthash].css'
            }),
            new cleanWebpackPlugin(['dist/*'], {
                root: path.resolve(__dirname, '../')
            }),
            new CopyWebpackPlugin([
                {
                    from: path.resolve(__dirname, '../static'),
                    to: '../static',
                    ignore: ['.*']
                }
            ]),
            new HtmlWebpackPlugin({
                title: 'admin',
                favicon: './static/favicon.ico',
                filename: '../index.html',
                template: '!!ejs-loader!./src/template/index.ejs',
                inject: false
            })
        ]
    });
    复制代码

    生产环境

    1.使用MiniCssExtractPlugin,来拆分css,我可以可以options里面有两个值filename和chunkFilename, filename指的是entry中key生成的css名称, chunkFilename是webpack中每个chunk拆分生成css的名称。

    2.使用OptimizeCSSAssetsPlugin 对打包之后的css文件进行压缩,

    3.使用splitChunks对公共代码进行抽取缓存,我们先来看一下这个插件的默认配置

    module.exports = {
        optimization: {
            splitChunks: {
                chunks: 'async',  "initial" | "all"(推荐) | "async" (默认就是async)
                minSize: 30000, 最小尺寸,30000
                maxSize: 0, 最小尺寸
                minChunks: 1, 最小 chunk ,默认1
                maxAsyncRequests: 5, // 最大异步请求数, 默认5
                maxInitialRequests: 3, // 最大初始化请求书,默认3
                automaticNameDelimiter: '~', // 打包分隔符
                name: true,
                cacheGroups: { // 重点,缓存配置
                    vendors: {
                        test: /[\\/]node_modules[\\/]/, // 只缓存node_modules里面的模块
                        priority: -10 // // 缓存组优先级,可能有多个
                    },
                }
            }
        }
    };
    复制代码

    看下我的配置

    splitChunks: {
        cacheGroups: {
            // 缓存组
            commons: {
                test: /[\\/]node_modules[\\/]/, // 只抽取引入的node_modules文件
                name: 'vender-exten', // 要缓存的 分隔出来的 chunk 名称
                chunks: 'all' // 对所有的chunk都进行缓存
            }
        }
    }
    复制代码

    通过webpack-bundle-analyzer生成的可视化图标分析查看项目中的多个chunk共同引入的lib包

    抽离5个依赖的lib包,进行缓存

    4.使用optimization.runtimeChunk,去缓存生成chunk过程中生成的webpack公用代码

    5.使用TerserJSPlugin对js进行压缩

    展开全文
  • webpack v1 迁移webpack v2 新特性 欢迎小伙伴们为 前端导航平台 点star github仓库: https://github.com/pfan123/fr...访问 前端导航平台 Tree Shaking Tree shaking 是一个术语,通常用来描述移除 ...
        

    从 webpack v1 迁移到 webpack v2 新特性

    欢迎小伙伴们为 前端导航平台 点star
    github仓库: https://github.com/pfan123/fr...
    访问 前端导航平台

    Tree Shaking

    Tree shaking 是一个术语,通常用来描述移除 JavaScript 上下文中无用代码这个过程,或者更准确的说是按需引用代码,它依赖于 ES2015 模块系统中 import/export 的静态结构特性。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup

    webpack 2 原生支持ES6模块 (别名 harmony modules) ,并能检测出未使用的模块输出。

    示例:举一个 maths.js 库例子,它输出两个方法 square 和 cube:

    // 这个函数没有被其他地方引用过
    export function square(x) {
        return x * x;
    }
    
    // 这个函数被引用了
    export function cube(x) {
        return x * x * x;
    }

    在 main.js 中我们只引用 cube 方法:

    import {cube} from './maths.js';
    console.log(cube(5)); // 125

    运行 node_modules/.bin/webpack main.js dist.js 并检查 dist.js 可发现 square 没有被输出:

    /* ... webpackBootstrap ... */
    /******/ ([
    /* 0 */
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    /* unused harmony export square */
    /* harmony export (immutable) */ __webpack_exports__["a"] = cube;
    // 这个函数没有被其他地方引用过
    function square(x) {
      return x * x;
    }
    
    // 这个函数被引用了
    function cube(x) {
      return x * x * x;
    }
    
    /***/ }),
    /* 1 */
    /***/ (function(module, __webpack_exports__, __webpack_require__) {
    
    "use strict";
    Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
    /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__maths_js__ = __webpack_require__(0);
    
    console.log(__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__maths_js__["a" /* cube */])(5)); // 125
    
    /***/ })

    resolve.root, resolve.fallback, resolve.modulesDirectories

    上述三个选项将被合并为一个标准配置项:resolve.modules. 更多关于resolve的信息信息可查阅 resolving.

      resolve: {
    -   root: path.join(__dirname, "src")
    +   modules: [
    +     path.join(__dirname, "src"),
    +     "node_modules"
    +   ]
      }

    resolve.extensions

    该配置项将不再要求强制转入一个空字符串,而被改动到了resolve.enforceExtension下, 更多关于resolve的信息信息可查阅 resolving.

    resolve.*

    更多相关改动和一些不常用的配置项在此不一一列举,大家如果在实际项目中用到可以到resolving)中进行查看.

    module.loaders 将变为 module.rules

    旧版本中loaders配置项将被功能更为强大的rules取代,同时考虑到新旧版本的兼容,之前旧版本的module.loaders的相关写法仍旧有效,loaders中的相关配置项也依旧可以被识别。

    新的loader配置规则会变得更加通俗易用,因此官方也非常推荐用户能及时按module.rules中的相关配置进行调整升级。

      module: {
    -   loaders: [
    +   rules: [
          {
            test: /\.css$/,
    -       loaders: [
    +       use: [
              {
                loader: "style-loader"
              },
              {
                loader: "css-loader",
    -           query: {
    +           options: {
                  modules: true
                }
              }
            ]
          },
          {
            test: /\.jsx$/,
            loader: "babel-loader", // Do not use "use" here
            options: {
              // ...
            }
          }
        ]
      }

    链式loaders

    同webpack1.X中类似,loaders继续支持链式写法,可将相关正则匹配到的文件资源数据在几个loader之间进行共享传递,详细使用说明可见 rule.use

    在wepback2中,用户可通过use项来指定需要用到的loaders列表(官方推荐),而在weback1中,如果需要配置多个loaders则需要依靠简单的 !符来切分,这种语法出于新旧兼容的考虑,只会在module.loaders中生效。

      module: {
    -   loaders: {
    +   rules: {
          test: /\.less$/,
    -     loader: "style-loader!css-loader!less-loader"
    +     use: [
    +       "style-loader",
    +       "css-loader",
    +       "less-loader"
    +     ]
        }
      }

    module名称后自动自动补全 -loader的功能将被移除

    在配置loader时,官方不再允许省略-loader扩展名,loader的配置写法上将逐步趋于严谨。

      module: {
        rules: [
          {
            use: [
    -         "style",
    +         "style-loader",
    -         "css",
    +         "css-loader",
    -         "less",
    +         "less-loader",
            ]
          }
        ]
      }

    当然,如果你想继续保持之前的省略写法,你写可以在resolveLoader.moduleExtensions中开启默认扩展名配置,不过这种做法并不被推荐。

    + resolveLoader: {
    +   moduleExtensions: ["-loader"]
    + }

    可以从这里查看 #2986此次变更的原因;

    json-loader无需要独立安装

    当我们需要读取json格式文件时,我们不再需要安装任何loader,webpack2中将会内置 json-loader,自动支持json格式的读取(喜大普奔啊)。

      module: {
        rules: [
    -     {
    -       test: /\.json/,
    -       loader: "json-loader"
    -     }
        ]
      }

    为何需要默认支持json格式官方的解释是为了在webpack, node.js and browserify三种构建环境下提供无差异的开发体验。

    loader配置项将默认从context中读取

    在webpack 1中的一些特殊的loader在读取对应资源时,需要通过require.resolve指定后才能指定生效。从webpack 2后,配置loader在直接从context中进行读取,这就解决了一些在使用“npm链接”或引用模块之外的context造成的模块重复导入的问题。

    配置中可以删除如下代码:

      module: {
        rules: [
          {
            // ...
    -       loader: require.resolve("my-loader")
    +       loader: "my-loader"
          }
        ]
      },
      resolveLoader: {
    -   root: path.resolve(__dirname, "node_modules")
      }

    module.preLoadersmodule.postLoaders 将被移除

      module: {
    -   preLoaders: [
    +   rules: [
          {
            test: /\.js$/,
    +       enforce: "pre",
            loader: "eslint-loader"
          }
        ]
      }

    之前需要用到preLoader的地方可以改到rules的enfore中进行配置。

    UglifyJsPlugin中的 sourceMap配置项将默认关闭

    UglifyJsPlugin中的sourceMap 默认项将从 true变为 false

    这就意味着当你的js编译压缩后,需要继续读取原始脚本信息的行数,位置,警告等有效调试信息时,你需要手动开启UglifyJsPlugin 的配置项:sourceMap: true

      devtool: "source-map",
      plugins: [
        new UglifyJsPlugin({
    +     sourceMap: true
        })
      ]

    UglifyJsPlugin 的警告配置将默认关闭

    UglifyJsPlugin中的 compress.warnings 默认项将从 true变为 false

    这就意味着当你想在编译压缩的时候查看一部分js的警告信息时,你需要将compress.warnings 手动设置为 true

      devtool: "source-map",
      plugins: [
        new UglifyJsPlugin({
    +     compress: {
    +       warnings: true
    +     }
        })
      ]

    UglifyJsPlugin 不再支持让 Loaders 最小化文件的模式了

    UglifyJsPlugin 将不再支持让 Loaders 最小化文件的模式。debug 选项已经被移除。Loaders 不能从 webpack 的配置中读取到他们的配置项。

    loade的最小化文件模式将会在webpack 3或者后续版本中被彻底取消掉.

    为了兼容部分旧式loader,你可以通过 LoaderOptionsPlugin 的配置项来提供这些功能。

      plugins: [
    +   new webpack.LoaderOptionsPlugin({
    +     minimize: true
    +   })
      ]

    DedupePlugin 已经被移除

    webpack.optimize.DedupePlugin 不再需要. 从你以前的配置移除这个配置选项.

    BannerPlugin 配置项将有所改变

    BannerPlugin 将不再允许接受两个参数,而是只提供一个对象配置项.

      plugins: [
    -    new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
    +    new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
      ]

    OccurrenceOrderPlugin 将被内置加入

    不需要再针对OccurrenceOrderPlugin进行配置

      plugins: [
    -   new webpack.optimize.OccurrenceOrderPlugin()
      ]

    ExtractTextWebpackPlugin配置项将有所改变

    ExtractTextPlugin ] 1.0.0 在webpack v2将无法使用,你需要重新指定安装ExtractTextPlugin 的webpack2的适配版本.

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

    更新后的ExtractTextPlugin版本会针对wepback2进行相应的调整。

    ExtractTextPlugin.extract的配置书写方式将调整

    module: {
      rules: [
        test: /.css$/,
    -    loader: ExtractTextPlugin.extract("style-loader", "css-loader", { publicPath: "/dist" })
    +    loader: ExtractTextPlugin.extract({
    +      fallbackLoader: "style-loader",
    +      loader: "css-loader",
    +      publicPath: "/dist"
    +    })
      ]
    }

    new ExtractTextPlugin({options})的配置书写方式将调整

    plugins: [
    -  new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false })
    +  new ExtractTextPlugin({
    +    filename: "bundle.css",
    +    disable: false,
    +    allChunks: true
    +  })
    ]

    全量动态加载资源将默认失效

    只有使用一个表达式的资源依赖引用(i. e. require(expr)),现在将创建一个空的context,而不是一个context的完整目录。

    当在es2015的模块化中无法工作时,请最好重构这部分的代码,如果无法进行修改这部分代码,你可以在ContextReplacementPlugin中来提示编译器做出正确处理。

    Cli使用自定义参数作为配置项传入方式将做调整

    如果你随意将自定义参数通过cli传入到配置项中,如:

    webpack --custom-stuff

    // webpack.config.js
    var customStuff = process.argv.indexOf("--custom-stuff") >= 0;
    /* ... */
    module.exports = config;

    你会发现这将不会被允许,cli的执行将会遵循更为严格的标准。

    取而代之的是用一个接口来做传递参数配置。这应该是新的代替方案,未来的工具开发也可能依赖于此。

    webpack --env.customStuff

    module.exports = function(env) {
      var customStuff = env.customStuff;
      /* ... */
      return config;
    };

    查看更多介绍 CLI.

    require.ensureAMD require将采用异步式调用

    require.ensureamd require将默认采用异步的加载方式来调用,而非之前的当模块请求加载完成后再在回调函数中同步触发。

    require.ensure将基于原生的Promise对象重新实现,当你在使用 require.ensure 时请确保你的运行环境默认支持Promise对象,如果缺少则推荐使用安装polyfill.

    Loader的配置项将通过options来设置

    webpack.config.js中将不再允许使用自定义属性来配置loder,这直接带来的一个影响是:在ts配置项中的自定义属性将无法在被在webpack2中正确使用:

    module.exports = {
      ...
      module: {
        rules: [{
          test: /\.tsx?$/,
          loader: 'ts-loader'
        }]
      },
      // does not work with webpack 2
      ts: { transpileOnly: false }
    }

    什么是 options?

    这是一个非常好的提问,严格意义上来说,custom propertyoptions均是用于webpack loader的配置方式,从更通俗的说法上看,options应该被称作query,作为一种类似字符串的形式被追加到每一个loader的命名后面,非常类似我们用于url中的查询字符串,但在实际应用中功能要更为强大:

    module.exports = {
      ...
      module: {
        rules: [{
          test: /\.tsx?$/,
          loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false })
        }]
      }
    }

    options也可作为一个独立的字面对象量,在loader的配置中搭配使用。

    module.exports = {
      ...
      module: {
        rules: [{
          test: /\.tsx?$/,
          loader: 'ts-loader',
          options:  { transpileOnly: false }
        }]
      }
    }

    LoaderOptionsPlugin context

    部分loader需要配置context信息, 并且支持从配置文件中读取。这需要loader通过用长选项传递进来,更多loader的明细配置项可以查阅相关文档。

    为了兼容部分旧式的loader配置,也可以采用如下插件的形式来进行配置:

      plugins: [
    +   new webpack.LoaderOptionsPlugin({
    +     options: {
    +       context: __dirname
    +     }
    +   })
      ]

    debug

    debug作为loader中的一个调试模式选项,可以在webpack1的配置中灵活切换。在webpack2中,则需要loader通过用长选项传递进来,更多loader的明细配置项可以查阅相关文档。

    loder的debug模式在webpack3.0或者后续版本中将会被移除。

    为了兼容部分旧式的loader配置,也可以采用如下插件的形式来进行配置:

    - debug: true,
      plugins: [
    +   new webpack.LoaderOptionsPlugin({
    +     debug: true
    +   })
      ]

    Code Splitting with ES2015

    在webpack1中,你需要使用require.ensure实现chunks的懒加载,如:

    require.ensure([], function(require) {
      var foo = require("./module");
    });

    在es2015的 loader中通过定义import()作为资源加载方法,当读取到符合ES2015规范的模块时,可实现模块中的内容在运行时动态加载。

    webpack在处理import()时可以实现按需提取开发中所用到的模块资源,再写入到各个独立的chunk中。webpack2已经支持原生的 ES6 的模块加载器了,这意味着 webpack 2 能够理解和处理 importexport了。

    import()支持将模块名作为参数出入并且返回一个Promise对象。

    function onClick() {
      import("./module").then(module => {
        return module.default;
      }).catch(err => {
        console.log("Chunk loading failed");
      });
    }

    这样做的还有一个额外的好处就是当我们的模块加载失败时也可以被捕获到了,因为这些都会遵循Promise的标准来实现。

    值得注意的地方:require.ensure的第三个参数选项允许使用简单的chunk命名方式,但是import API中将不被支持,如果你希望继续采用函数式的写法,你可以继续使用require.ensure

    require.ensure([], function(require) {
      var foo = require("./module");
    }, "custom-chunk-name");

    (注: System.import将会被弃用,webpack中将不再推荐使用 System.import,官方也推荐使用import进行替换,详见 v2.1.0-beta.28)

    如果想要继续使用Babel中提供的import,你需要独立安装 dynamic-import 插件并且选择babel的Stage 3来捕获时的错误, 当然这也可以根据实际情况来操作而不做强制约束。

    Dynamic expressions动态表达式

    现在import()中的传参可支持部分表达式的写法了,如果之前有接触过CommonJS中require()表达式写法,应该不会对此感到陌生,(它的操作其实和 CommonJS 是类似的,给所有可能的文件创建一个环境,当你传递那部分代码的模块还不确定的时候,webpack 会自动生成所有可能的模块,然后根据需求加载。这个特性在前端路由的时候很有用,可以实现按需加载资源)

    import() 会针对每一个读取到的module创建独立的separte chunk

    function route(path, query) {
      return import(`./routes/${path}/route`)
        .then(route => new route.Route(query));
    }
    // This creates a separate chunk for each possible route

    可以混用 ES2015 和 AMD 和 CommonJS

    在 AMD 和 CommonJS 模块加载器中,你可以混合使用所有(三种)的模块类型(即使是在同一个文件里面)。

    // CommonJS consuming ES2015 Module
    var book = require("./book");
    
    book.currentPage;
    book.readPage();
    book.default === "This is a book";
    // ES2015 Module consuming CommonJS
    import fs from "fs"; // module.exports map to default
    import { readFileSync } from "fs"; // named exports are read from returned object+
    
    typeof fs.readFileSync === "function";
    typeof readFileSync === "function";

    注:es2015 balel 的默认预处理会把 ES6 模块加载器转化成 CommonJS 模块加载。要是想使用 webpack 新增的对原生 ES6 模块加载器的支持,你需要使用 es2015-webpack 来代替,另外如果你希望继续使用babel,则需要通过配置babel项,使其不会强制解析这部分的module symbols以便webpack能正确使用它们,babel的配置如下:

    .babelrc

    {
      "presets": [
        ["es2015", { "modules": false }]
      ]
    }

    Hints

    No need to change something, but opportunities

    Template strings模板字符串

    webpack中的资源参数已经开始支持模板字符串了,这意味着你可以使用如下的配置写法:

    - require("./templates/" + name);
    + require(`./templates/${name}`);

    配置支持项支持Promise

    webpack现在在配置文件项中返回Promise了,这就允许你在配置中可以进行一些异步的写法了,如下所示:

    webpack.config.js

    module.exports = function() {
      return fetchLangs().then(lang => ({
        entry: "...",
        // ...
        plugins: [
          new DefinePlugin({ LANGUAGE: lang })
        ]
      }));
    };

    Loader匹配支持更多的高级写法

    webpack中的loader配置支持如下写法:

    module: {
      rules: [
        {
          resource: /filename/, // matches "/path/filename.js"
          resourceQuery: /querystring/, // matches "/filename.js?querystring"
          issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js"
        }
      ]
    }

    更多的CLI参数项

    如下有更多的CLI 参数项可用:

    --define process.env.NODE_ENV="production" 支持直接配置DefinePlugin.

    --display-depth 能显示每个entry中的module的资源深度

    --display-used-exports 能显示每个module中依赖使用了哪些资源.

    --display-max-modules能限制显示output中引用到的资源数量 (默认显示15个).

    -p 指定当前的编译环境为生产环境,即修改:process.env.NODE_ENV"production"

    Cacheable缓存项

    Loaders 现在默认可被缓存。Loaders 如果不想被缓存,需要选择不被缓存。

      // Cacheable loader
      module.exports = function(source) {
    -   this.cacheable();
        return source;
      }
      // Not cacheable loader
      module.exports = function(source) {
    +   this.cacheable(false);
        return source;
      }

    Complex options复合参数项写法

    webpack v1 只支持能够「可 JSON.stringify的对象」作为 loader 的 options。

    webpack2中的loader参数项中已经可以支持任意的JS对象的写法了。

    使用复合选项时会有一个限制,你需要配置一个ident作为项来保证能正确引用到其他的loader,这意味着通过配置我们可以在内联写法中去调用对应依赖的加载器,如下:

    require("some-loader??by-ident!resource")

    {
      test: /.../,
      loader: "...",
      options: {
        ident: "by-ident",
        magic: () => return Math.random()
      }
    }

    v2.2.1之前(即从 v2.0.0 到 v2.2.0),使用 Complex options,需要在 options 对象上添加 ident,允许它能够被其他 loader 引用。这在 v2.2.1 中被删除,因此目前的迁移不再需要使用 ident 键。

    {
      test: /\.ext/
      use: {
        loader: '...',
        options: {
    -     ident: 'id',
          fn: () => require('./foo.js')
        }
      }
    }

    参考资料:
    webpack2.0
    webpack guide

    展开全文
  • 这次我们以inputPassword组件为例,将编译配置环境 从webpack3迁移webpack4,新装的webpack版本是4.14,但是配置文件还是用的webpack3的配置。 git地址:https://github.com/jean0218/react-inputPassword 先来...

    这次我们以inputPassword组件为例,将编译配置环境 从webpack3迁移至webpack4,新装的webpack版本是4.14,但是配置文件还是用的webpack3的配置。

    git地址:https://github.com/jean0218/react-inputPassword

    先来看看pack.json文件:

    {
      "name": "react-inputpassword",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "webpack": "webpack --config ./build/webpack.config.js",
        "start": "webpack-dev-server --config ./build/webpack.config.js",
        "dev": "webpack --config ./build/webpack.dev.config.js",
        "build": "webpack --progress --profile --colors --config ./build/webpack.pro.config.js"
      },
      "repository": {
        "type": "git",
        "url": "git+https://github.com/jean0218/react-inputPassword.git"
      },
      "author": "",
      "license": "ISC",
      "bugs": {
        "url": "https://github.com/jean0218/react-inputPassword/issues"
      },
      "homepage": "https://github.com/jean0218/react-inputPassword#readme",
      "dependencies": {
        "babel-core": "^6.26.3",
        "babel-loader": "^7.1.4",
        "babel-polyfill": "^6.26.0",
        "babel-preset-env": "^1.7.0",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-react": "^6.24.1",
        "babel-preset-stage-0": "^6.24.1",
        "css-loader": "^0.28.11",
        "enzyme-adapter-inferno": "^1.3.0",
        "extract-text-webpack-plugin": "^3.0.2",
        "file-loader": "^1.1.11",
        "html-webpack-plugin": "^3.2.0",
        "react": "^16.4.1",
        "react-dom": "^16.4.1",
        "react-test-renderer": "^16.4.1",
        "style-loader": "^0.21.0",
        "webpack": "^4.14.0",
        "webpack-dev-server": "^3.1.4",
        "webpack-merge": "^4.1.3"
      },
      "devDependencies": {
        "babel-jest": "^23.2.0",
        "enzyme": "^3.3.0",
        "enzyme-adapter-react-16": "^1.1.1",
        "jest": "^23.3.0"
      }
    }
    

    找到webpack配置文件,放在build目录下,原有webpack文件配置如下:

    webpack.base.config.js(webpack基础配置)

    const webpack = require('webpack');
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const fileEntry = require('./fileEntry.js');
    
    const webpackBaseConfig = {
        resolve: {
            extensions: [".js", ".json", ".jsx"],
            alias: {
                images: path.resolve(__dirname, '../examples/static/images'),
            }
        },
    
        entry: {
            examples:path.resolve(__dirname, '../examples/index.js'),
            demo01:path.resolve(__dirname, '../examples/demo01.js')
        },
        
        module: {
            noParse: /node_modules\/(jquey\.js)/,
            rules: [{
                test: /\.(js|jsx)$/,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        "presets": [
                            "es2015", 'stage-0', 'react'
                        ]
                    }
                }]       
            },{
                test: /\.(png|jpg|gif)$/,
                use: [{
                    loader: 'file-loader',
                    options: {
                        limit: 25000,
                        name: 'images/[name][hash:6].[ext]',
                        // 我们选择加载的图片格式为png,jpg,jpeg,gif,并限定当文件小于25kb,转换为base64编码。
                        // 优势:将一些小并且不常更新的图片转换base64编码后,可以减少一次或多次http请求。
                        // 但这个limit应该定义成一个合适的值,因为如果将稍大些的图片转为base64后,会生成大量字符,
                        // 反而降低我们的加载速度。
                    }
                }]
            },{
                test: /\.(woff|woff2|eot|ttf|svg|otf)$/,
                loader: 'file-loader',
                options: {
                    name: 'fonts/[name].[ext]'
                }
            }]
        },
    
        plugins: [
            new webpack.optimize.ModuleConcatenationPlugin(),
        ],
    }
    
    fileEntry.map(function(item) {//新文件输出 
        webpackBaseConfig.entry[item.fileName] =  path.resolve(__dirname, item.sourceFile);
        const chunksSort = item.chunks
        const htmlPackage = new HtmlWebpackPlugin({
            //favicon: 'path/to/yourfile.ico',//给生成的 html 文件生成一个 favicon
            title: item.title, //生成的html文档的标题
            template: path.resolve(__dirname, item.template),
            filename: item.targetFile, //输出文件的文件名称,默认为index.html,可以配置输出文件指定目录位置,例如'html/index.html'
            //filename配置的html文件目录是相对于webpackConfig.output.path路径而言的,不是相对于当前项目目录结构的。
            //指定生成的html文件内容中的link和script路径是相对于生成目录下的,写路径的时候请写生成目录下的相对路径。
            //hash: false,//true|false,是否为所有注入的静态资源添加webpack每次编译产生的唯一hash值
            showErrors: true, //是否将错误信息输出到html页面中,便于调试
            //inject: 'body', //所有JavaScript资源插入到body元素的底部
            chunks: item.chunks,
            //允许插入到模板中的一些chunk,不配置此项默认会将entry中所有的thunk注入到模板中。
            //在配置多个页面时,每个页面注入的thunk应该是不相同的,需要通过该配置为不同页面注入不同的thunk;
            //excludeChunks: ,//这个与chunks配置项正好相反,用来配置不允许注入的thunk。
            chunksSortMode: (argument, argument2) =>{
                //none | auto| function,默认auto; 允许指定的thunk在插入到html文档前进行排序。
                //function值可以指定具体排序规则;auto基于thunk的id进行排序; none就是不排序
                var aIndex = chunksSort.indexOf(argument.names[0]);
                var bIndex = chunksSort.indexOf(argument2.names[0]);
                aIndex = aIndex < 0 ? chunksSort.length + 1 : aIndex;
                bIndex = bIndex < 0 ? chunksSort.length + 1 : bIndex;
                return aIndex - bIndex;
            } 
        });           
        webpackBaseConfig.plugins.push(htmlPackage);
    });
    
    module.exports = webpackBaseConfig;

    其中的fileEntry.js文件主要用于生成html文件,这里就不再贴出来了。

    webpack.config.js(本地运行环境配置)

    const webpack = require('webpack');
    const path = require('path');
    const webpackBaseConfig = require('./wepback.base.config.js');
    const merge = require('webpack-merge');
    const outputDir = 'dist';
    
    
    
    const webpackConfig = merge(webpackBaseConfig, {
        devtool: 'cheap-module-eval-source-map',
        output: {
            path: path.resolve(__dirname, '../' + outputDir + '/'),
            filename: 'js/[name].js',
            chunkFilename: 'js/[name].chunks.js',
        },
        module: {
            rules: [
                {
                    test: /\.css$/, 
                    use:[
                        'style-loader',
                        'css-loader'
                    ]
                }
            ],
        },
        plugins: [
            new webpack.HotModuleReplacementPlugin(),
        ],
    });
    
    
    module.exports = webpackConfig;

    我们来看看webpack4相对于3新增了哪些内容:

    1、不止需要安装webpack,还需要安装webpack-cli

    在webpack3中,webpack本身和它的cli以前都在同一个包中,但在第4版中,它们两者已经分开,所以我们的webpack需要安装两个包,全局安装webpack

     npm install webpack -g

    再全局安装webpack-cli

    npm install webpack-cli -g

    安装完成后出现版本提示,就说明该包已经安装成功。

    (这个安装是在配置react-loadList组件时截图的,除了项目不同其它都是一样的)

     

    2、新增了mode参数来表示生产还是开发

    按照以上配置,我们运行 npm run start,文件能正常编译,但会看到如下警告:

    这个警告告诉我们,'mode'选项没有被设置,必须设置'mode'选项。webpack4新增了mode参数来表示生产还是开发,新增的参数有两个可选值:development和production。不可缺省,缺省就会像上图一样报警告,其中

    production 模式:

    • 默认提供所有可能的优化,如代码压缩/作用域提升等

    • 不支持 watching

    • process.env.NODE_ENV 的值不需要再定义,默认是 production

    development 模式:

    • 主要优化了增量构建速度和开发体验

    • process.env.NODE_ENV 的值不需要再定义,默认是 development

    • 开发模式下支持注释和提示,并且支持 eval 下的 source maps

    可以在pack.json中配置

    webpak --mode development

    也可以配置文件中配置:

    mode:'development',
    devtool: 'cheap-module-eval-source-map',

    如果原有的文件中有new webpack.DefinePlugin,加上mode选项后,则需要删除 

    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") })

    再运行npm run start,这个时候警告已经没有了。

     

    3、rules中需要增加type类型,指定模块类型

    webpack 4之前,js 是 webpack 中的唯一模块类型,因而不能有效地打包其它类型的文件。而 webpack 4 则提供了 5 种模块类型:

    • javascript/auto: (webpack 3中的默认类型)支持所有的JS模块系统:CommonJS、AMD、ESM
    • javascript/esm: EcmaScript 模块,在其他的模块系统中不可用(默认 .mjs 文件)
      • 相较于javascript/auto模式更严格,导入的名称必须存在于导入的模块中
      • 动态的模块(非ESM, 如CommonJs)只能通过import导入,其它方式的导入都会报错
    • javascript/dynamic: 仅支持 CommonJS & AMD,EcmaScript 模块不可用
    • json: 可通过 require 和 import 导入的 JSON 格式的数据(默认为 .json 的文件)
    • webassembly/experimental: WebAssembly 模块(处于试验阶段,默认为 .wasm 的文件)

    (我在看到这块时,产生了一个疑问,这些都是js的模型,图片、字体类的不需要增加type类型么?待以后有机会再补充)

     

    5、CommonsChunkPlugin需要替换

         本次更新内容中没有这一项,暂时不编写,以后更新。

     

    这样,我们的webpack3成功迁移至4了,相对于2迁移至3是不是简单了很多。

     

    参考:

    https://blog.csdn.net/qq_26733915/article/details/79446460

    https://blog.csdn.net/VhWfR2u02Q/article/details/79366615

     

     

    展开全文
  • 主要介绍了webpack 4 升级迁移的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 本篇文章主要介绍了webpack4的迁移的使用方法,主要介绍了如何从webpack1.x升级到4.x,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • webpack4的迁移

    2018-06-23 21:14:00
    感觉是突然之间,webpack4的消息就满天飞了,听说打包速度提高了很多,还有最大的噱头是实现了零配置,leader有一天就吩咐我说,有时间把我们的项目也升个级呗。好嘞。 1.x到2.x 这次升级跨度比较大,我们是从...
  • 由此而来的还有之前webpack3.x的项目如何迁移到新的webpack版本,本文就一个新的vue-cli创建的基于webpack的项目进行迁移。 题外话:不要看0配置是很有噱头,基本是不能满足大部分用户啊的需求,不过加入了更多的...
  • parcel简介 Parcel, 是一个网络应用打包工具, 适用于经验不同的开发者. 它利用多核处理提供了极快的速度, 并且不需要任何...对于现阶段来说, 对已有的成熟的webpack项目, 玩一下还是可以的, 但是不建议公司项目迁移,...
  • Webpack4

    2020-12-02 02:06:50
    <div><p>webpack迁移到4.x</p><p>该提问来源于开源项目:brickspert/react-family</p></div>
  • webpack4升级指南以及从webpack3.x迁移

    万次阅读 2018-03-05 16:35:47
    由此而来的还有之前webpack3.x的项目如何迁移到新的webpack版本,本文就一个新的vue-cli创建的基于webpack的项目进行迁移。 题外话:不要看0配置是很有噱头,基本是不能满足大部分用户啊的需求,不过加...
  • webpack1.x至webpack3.x迁移踩坑

    千次阅读 2017-12-27 14:41:30
    今天将我自己的手脚架从webpack1.x迁移webpack3.x,途中一切顺利,跟着迁移文档: 1: http://www.css88.com/doc/webpack2/guides/migrating/ 其中比较坑爹的2点是: 1:postcss配置。。。需要在根目录创建post...
  • 之前自己做react的webpack环境配置总觉得差强人意,于是就把vue-cli的迁移过来,感觉还是不错的。对应一般开发需要,下面需要修改的就在build和config目录下的几个文件中     从webpack.base.conf.js 文件...
  • 不完全迁移指北 环境 不再支持 Node.js 4。 根据 <code>package.json</code> 配置, Node.js 的最低支持版本为 <code>6.11.5</code></p> 模块类型 <p>webpack 4之前,js 是 webpack 中的唯一模块类型,...
  • 主要介绍了React 项目迁移 Webpack Babel7的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • webpack 从 v1 迁移到 v2

    2017-05-04 20:07:24
    resolve.root, resolve.fallback, resolve.modulesDirectories 上述配置项被一个单独的配置项 resolve.modules 取代。详见 resolving。 resolve: { - root: path.join(__dirname, "src") + modules: [...
  • [原简书]webpack4的迁移

    2018-08-18 13:49:25
    感觉是突然之间,webpack4的消息就满天飞了,听说打包速度提高了很多,还有最大的噱头是实现了零配置,leader有一天就吩咐我说,有时间把我们的项目也升个级呗。好嘞。 1.x到2.x 这次升级跨度比较大,我们是从...
  • 腾讯NOW直播IVWEB团队之前一直采用Fis构建,本篇文章主要介绍从Fis迁移webpack遇到的问题和背后的黑科技,内容包括inline-resource、多页面构建、资源压缩、文件hash、文件目录规则等等。 为什么要迁移webpack? ...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 287
精华内容 114
关键字:

webpack迁移