[Turn] Those pits that have been stepped on when using webpack

The process of using webpack is a process of constantly entering and exiting the pit. Looking back at the road, there are pits all the way! Now, sort out the pits that have been traversed. Blessed are all the officials~

The version information of the dependencies I used is at the end of the article. If you find a problem that is inconsistent with my description in this article, you can check if the version is different from what I use.

1. Problems caused by differences between Mac platform and Windows platform

1. Differences in paths

When configuring the entry option, I configured it like this:

entry: {
    main: __dirname + '/src/index.js'
}

This is completely fine under Mac, but it will report an error under Windows:

ERROR in Entry module not found: Error: Can't resolve 'd:\demo\config/src/index.js' in 'd:\demo'

This is because the paths of the two platforms are different. Mac is /, and Windows is \.

The solution is:

const path = require('path');
const entryPath = path.resolve(__dirname, '/src/index.js');
entry: {
    main: entryPath
}

2. Differences in setting node environment variables

On Mac, this can be configured in package.json:

"scripts": {
     "build":"NODE_ENV=production && ..."
}

But not in Windows. To solve this problem, you need to use the cross-env module.

Install it first:

npm i cross-env --save-dev

Then change the above configuration to:

"scripts": {
     "build":"./node_modules/.bin/cross-env NODE_ENV=production && ..."
}

Second, the pit in the babel configuration

For the configuration of babel, two problems are prone to occur:

1. It is easy to reduce one layer of [] when configuring presets.

It is problematic to configure it like this:

presets: [
   'es2015',
   'react',
   'stage-2'
],

This will give an error when packaging:

Using removed Babel 5 option: foreign.modules -
Use the corresponding module transform plugin in the `plugins` option

In babel 6, this layer [] must be included here, and the complete should be written as follows.

{
    test: /\.(js|es|es6|jsx)$/,
    use: [
        {
            loader: 'babel-loader',
            options: {
               presets: [
                   ['es2015', {modules: false, loose: true}],
                   ['react'],
                   ['stage-2']
               ],
               plugins: [
                   ['transform-runtime']
               ],
               comments: false,
               cacheDirectory: true
            }
        },
        {
            loader: 'eslint-loader',
            options: {
                configFile: eslintConfigPath
            }
        }
    ],
    exclude: excludeReg
},

The modules: falseconfiguration item is to tell es2015 preset to avoid compiling import statements into CommonJS, so that Webpack can do tree shaking.

2. It is easy to ignore the babel statement to be transcoded in the .vue file.

If configured as above, transcoding of .js, .es, .es6, .jsx and other JavaScript files is not a problem, but these configurations cannot affect .vue files. However, when the .vue file is compiled, vue-loader will load the configuration in .babelrc by default. Therefore, we should write these babel configurations into the .babelrc file so that it can be shared with the compilation of the .vue file. Make these configuration items work when both JavaScript files and .vue files are compiled.

Therefore, we extract the configuration options of babel and put them in the .bablerc file. The code is:

{
    presets: [
        ["react"],
        [
            "es2015", {"modules": false, "loose": true}
        ],
        ["stage-2"]
    ],
    plugins: [
        ["transform-runtime"]
    ],
    comments: false
}

The modified babel-loader configuration is:

{
    test: /\.(js|es|es6|jsx)$/,
    use: [
        {
            loader: 'babel-loader',
            options: {
               cacheDirectory: true
            }
        },
        {
            loader: 'eslint-loader',
            options: {
                configFile: eslintConfigPath
            }
        }
    ],
    exclude: excludeReg
},

3. Dealing with unmodularized libraries such as Zepto

For unmodularized libraries, if they are direct import, an error will be reported when webpack is packaged. For details, see: https://juejin.im/entry/588ca3018d6d81006c237c85

The solution is to add the following configuration items under the rules of the module:

{
    test: require.resolve('zepto'),
    loader: 'exports-loader?window.Zepto!script-loader'
}

Among them, require.resolve() is the method that nodejs uses to find the location of the module, and returns the entry file of the module, for example, zepto is ./node_modules/zepto/dist/zepto.js.

In addition, there are two loaders used here, we need to install them first:

npm i --save-dev script-loader exports-loader

Fourth, the root configuration item of clean-webpack-plugin cannot be less

var CleanWebpackPlugin = require('clean-webpack-plugin');
new CleanWebpackPlugin(baseConfig.output.path, {
    root: rootPath,
    verbose: true
}),

This root configuration item cannot be missing, otherwise the following prompt will appear and the clean operation will be skipped.

clean-webpack-plugin: ...\build is outside of the project root. Skipping...

In addition, this verbose configuration item is a bit confusing. Verbose means verbose, long-winded. The actual meaning is Write logs to console, that is, whether to output logs to the terminal.

Five, the pit of extract-text-webpack-plugin

1. Currently, this plugin cannot be used when using web-dev-server

When using web-dev-server, do not use extract-text-webpack-plugin, it is currently not supported. See: https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/384

2. If there are multiple configuration files of webpack (such as webpack.base.config.js, webpack.dev.config.js, webpack.prod.config.js, etc.), the Object.assignlatter configuration file will The plugins option of a file is overwritten, or when the plugins option is mistakenly placed under the module in the configuration file, the following error will be reported because the configuration of the extract-text-webpack-plugin plugin is missing under the plugins option. Difficult to troubleshoot error causes:

Module build failed: Error: "extract-text-webpack-plugin" loader is used without the corresponding plugin

See: https://github.com/webpack/extract-text-webpack-plugin/issues/50

6. When using less-loader, the less module must be installed at the same time. When the less-loader module is installed separately, the less module will not be automatically installed

When using less-loader, the less module must be installed at the same time, otherwise an error will be reported:

Module build failed: Error: Cannot find module 'less'。

less-loader needs to rely on less to implement. Because less in npm3.0+ is not automatically installed with less-loader.

7. Misuse of hash, chunkhash, and contenthash

These three "ghost things" are really easy for people to be foolishly confused!

For the distinction between hash and chunkhash, see: http://www.cnblogs.com/ihardcoder/p/5623411.html

Chunkhash changes with the content of a specific chunk, that is, the hash value calculated based on the content of a specific chunk. When webpack calculates chunkhash, it is calculated separately according to different entry files. When part of the content of the chunk changes (whether it is js or css), the chunkhash will be recalculated. webpack uses NodeJS built-in crypto module to compute chunkhash. Each chunk resource generates a chunkhash associated with its content.

The hash is generated with the compilation, and after any file in the project is changed, a new compilation will be created, and the corresponding hash value will be updated. Hash can be understood as the hash value of the overall project file, not for a specific chunk. i.e. it is the hash affected by all chunks. Each compilation generates a unique hash, but all resources are marked with the same hash, which cannot fulfill the requirement of persistent cache.

Some people say that in the hot update mode, after changing the hash to chunkhash, the vendors file will become undefined. I have tried many parameter transfer formats, but the goal still cannot be achieved. Finally, I found that this is only the case in the webpack hot update mode, and because the development environment can ignore version control, the configuration in the two environments is split to solve this problem.

Do not use [chunkhash]/[hash]/[contenthash] in the development environment, because there is no need to do persistent caching in the development environment, and this will increase the compilation time, so use [name] in the development environment.

extract-text-webpack-plugin provides another hash value: contenthash. As the name implies, contenthash represents the hash value of the content of the text file, that is, only the hash value of the style file.

Because it can be configured in production environment:

new ExtractTextWebpackPlugin({
    filename: 'css/[name].[contenthash].css',
    allChunks: true
})

Plugins that should also generate stable module IDs on production config:

new webpack.HashedModuleIdsPlugin(),

Eight, new webpack.optimize.UglifyJsPluginpackaging errors

Note that the current version of UglifyJsPlugin will report the following errors when packaging:

ERROR in build.js from UglifyJsSyntaxError:
Unexpected token punc «(», expected punc «:»

The reason is that this plugin depends on uglify-js, but the current version of uglify-js does not support ES6 code compression. The solution is:

Add the following dependencies to the devDependencies of package.json and execute it again npm install.

"uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony"

See also: https://github.com/webpack-contrib/uglifyjs-webpack-plugin

new webpack.optimize.UglifyJsPlugin({
    mangle: { // 排除不想要压缩的对象名称
        except: ['$', 'exports', 'require', 'module']
    },
    compress: {
        // http://lisperator.net/uglifyjs/compress
        warnings: false,    // warn about potentially dangerous optimizations/code
        conditionals: true, // optimize if-s and conditional expressions
        unused: true,       // drop unused variables/functions
        comparisons: true,  // optimize comparisons
        sequences: true,    // join consecutive statements with the "comma operato"
        dead_code: true,    // discard unreachable code 丢弃未使用的代码
        evaluate: true,     // evaluate constant expressions
        join_vars: true,    // join var declarations
        if_return: true     // optimize if-s followed by return/continue
    },
    output: {
        // https://github.com/mishoo/UglifyJS2/blob/master/lib/output.js
        comments: false
    },
    sourceMap: false         //将错误信息的位置映射到模块。这会减慢编译的速度。仅在开发环境下使用。
}),

By the way, pay attention to the configuration of those compression options of UglifyJsPlugin above.

It is the unused and dead_code options that allow tree shaking.

9. new webpack.optimize.CommonsChunkPluginErrors caused by forgetting to import or importing the wrong order in the packaged public files

Note: If a common file is generated using CommonsChunkPlugin, but the common file generated by CommonsChunkPlugin is not introduced into the page or the location where the common file is introduced is not in front of other JS files packaged with webpack, an error will appear when browsing the page:

Uncaught ReferenceError: webpackJsonp is not defined

To ensure that these files are imported in the correct order, you need to add this configuration item to the configuration item of the html-webpack-plugin plugin:

// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'

Attachment: List of Dependent Module Version Information

"dependencies": {
    "babel-polyfill": "^6.23.0",
    "element-ui": "^1.2.5",
    "es6-promise": "^4.1.0",
    "vue": "^2.2.4",
    "vue-router": "^2.3.0",
    "vuex": "^2.2.1",
    "zepto": "^1.2.0"
},
"devDependencies": {
    "autoprefixer": "^6.6.1",
    "babel-core": "^6.22.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-es2015-webpack": "^6.4.3",
    "babel-preset-latest": "^6.22.0",
    "babel-preset-react": "^6.23.0",
    "babel-preset-stage-2": "^6.22.0",
    "clean-webpack-plugin": "^0.1.15",
    "css-loader": "^0.26.1",
    "eslint": "^3.14.0",
    "eslint-config-airbnb": "^14.0.0",
    "eslint-loader": "^1.6.1",
    "eslint-plugin-html": "^2.0.1",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "^3.0.2",
    "eslint-plugin-react": "^6.9.0",
    "exports-loader": "^0.6.4",
    "expose-loader": "^0.7.3",
    "extract-text-webpack-plugin": "^2.0.0-beta.5",
    "file-loader": "^0.9.0",
    "glob": "^7.1.1",
    "html-loader": "^0.4.5",
    "html-webpack-plugin": "^2.26.0",
    "ink-docstrap": "^1.3.0",
    "jsdoc-webpack-plugin-v2": "0.0.1",
    "less": "^2.7.2",
    "less-loader": "^2.2.3",
    "node-sass": "^4.3.0",
    "path": "^0.12.7",
    "postcss-loader": "^1.2.2",
    "sass-loader": "^4.1.1",
    "script-loader": "^0.7.0",
    "style-loader": "^0.13.1",
    "uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony",
    "url-loader": "^0.5.7",
    "vue-loader": "^11.1.4",
    "vue-template-compiler": "^2.2.4",
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.2.0"

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324852536&siteId=291194637