webpack4入门

作者: 草珊瑚_6557 | 来源:发表于2018-03-09 19:41 被阅读1812次

    前提

    • 已安装node(版本号>4.0,已自带NPM)
    • mac机器
    • 有一个空目录

    要实现的功能

    • JSX语法,ES6语法,LESS语法编写的模块转化为浏览器可执行的模块
    • 代码的混淆压缩
    • 多页面多入口
    • 提取公共文件

    无webpack.config.js配置打包

    1. 快速构建package.json文件。
      npm init -y

    2. 安装webpack4及其命令行接口
      npm i webpack webpack-cli --save-dev

    3. package.json文件增加build参数

    "scripts": {
      "build": "webpack"
    }
    
    1. 创建./src/index.js文件
      增加内容
    console.log(`这是入口文件`);
    
    1. 终端执行npm run build
      目录下多了一个./dist/main.js
      这个文件是webpack./src/index.js的打包结果。

    productiondevelopment模式

    1. 修改package.json文件的scripts字段
    "scripts": {
      "dev": "webpack --mode development",
      "build": "webpack --mode production"
    }
    
    1. 分别执行npm run devnpm run build
      你会看到./dist/main.js不同的变化。
      production模式下,默认对打包的进行minification(文件压缩),Tree Shaking(只导入有用代码),scope hoisting(作用域提升)等等操作。
      总之是让打包文件更小。
      development模式下,对打包文件不压缩,同时打包速度更快。

    如果没指定任何模式,默认是production模式。

    ES6和React

    1. 安装对应依赖包
      npm i babel-core babel-loader babel-preset-env react react-dom babel-preset-react --save-dev

    2. 新建.babelrc文件,进行相关配置

    {
      "presets": ["env", "react"]
    }
    
    1. 新建webpack.config.js文件,进行相关配置
    module.exports = {
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: "babel-loader"
            }
          }
        ]
      }
    };
    
    1. 新增./src/app.js以及修改./src/index.js
      ./src/app.js内容如下:
    import React from "react";
    import ReactDOM from "react-dom";
    const App = () => {
      return (
        <div>
          <p>React here!</p>
        </div>
      );
    };
    export default App;
    ReactDOM.render(<App />, document.getElementById("app"));
    

    ./src/index.js内容如下:

    import App from "./App";
    
    1. 终端执行npm run build

    使用html-webpack-plugin插件对html进行打包

    新建./src/index.html文件,内容如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>webpack4入门</title>
    </head>
    <body>
        <div id="app">
        </div>
    </body>
    </html>
    

    安装依赖包。

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

    修改webpack.config.js配置。

    const HtmlWebPackPlugin = require("html-webpack-plugin");
    module.exports = {
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: "babel-loader"
            }
          },
          {
            test: /\.html$/,
            use: [
              {
                loader: "html-loader",
                options: { minimize: true }
              }
            ]
          }
        ]
      },
      plugins: [
        new HtmlWebPackPlugin({
          template: "./src/index.html",
          filename: "./index.html"
        })
      ]
    };
    

    终端执行npm run build命令。
    你会看到项目多了个./dist/index.html文件。

    使用webpack-dev-server插件

    安装依赖包。
    npm i webpack-dev-server --save-dev

    修改package.json文件。

    "scripts": {
      "start": "webpack-dev-server --mode development --open",
      "build": "webpack --mode production"
    }
    

    修改webpack.config.js文件,新增devServer配置。

    devServer: {
        contentBase: require('path').join(__dirname, "dist"),
        compress: true,
        port: 8033,
        host: "127.0.0.1",
    }
    

    终端执行npm run start便可以启动webpack dev server

    使用Hot Module Replacement

    Hot Module Replacement有针对React,Vue,Redux,Angular,样式等等。
    这里我们以React Hot Loader为例。

    安装依赖包。

    npm i react-hot-loader --save-dev
    

    修改.babelrc文件,新增plugins选项。

    {
      "plugins": ["react-hot-loader/babel"]
    }
    

    修改webpack.config.js文件。

    const path = require('path');
    const HtmlWebPackPlugin = require("html-webpack-plugin");  
    const webpack = require('webpack'); // 新增
    module.exports = {
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: {
                        loader: "babel-loader"
                    }
                },
                {
                    test: /\.html$/,
                    use: [
                        {
                            loader: "html-loader",
                            options: { minimize: true }
                        }
                    ]
                }
            ]
        },
        devtool: 'inline-source-map',
        plugins: [
            new HtmlWebPackPlugin({
                template: "./src/index.html",
                filename: "./index.html"
            }),
            new webpack.NamedModulesPlugin(), // 新增
            new webpack.HotModuleReplacementPlugin() //新增
        ],
        devServer: {
            contentBase: path.join(__dirname, "dist"),
            compress: true,
            port: 8033,
            host: "127.0.0.1",
            hot: true // 新增
        }
    };
    

    修改./src/app.js文件内容如下:

    import React from "react";
    import ReactDOM from "react-dom";
    import { hot } from 'react-hot-loader' // 新增
    
    const App = () => {
      return (
        <div>
          <p>这是一个测试文件!真得是动态更新啊</p>
          <div>好棒棒啊</div>
        </div>
      );
    };
    export default hot(module)(App); // 修改
    ReactDOM.render(<App />, document.getElementById("app"));
    

    终端执行npm run start便可以启动webpack dev server
    然后修改./src/app.js看下效果。

    动态加模块

    • 动态加载普通JS模块
      修改.babelrc文件添加"syntax-dynamic-import"插件
    {
        "presets": [
            "env",
            "react"
        ],
        "plugins": ["react-hot-loader/babel","syntax-dynamic-import"]
    }
    

    然后在业务代码文件使用import语法即可

    import('模块路径').then(mod => {
      someOperate(mod); //mod是module的简写,表示加载成功后的异步组件
    });
    

    如果没有使用syntax-dynamic-import插件会导致构建失败,并提示:

    Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level
    
    • 动态加载React模块
      如同动态加载普通JS模块,修改.babelrc文件添加"syntax-dynamic-import"插件。
      然后安装react-loadable这个NPM包
    npm install react-loadable --save
    

    接着如下方式引入React组件模块即可。

    import Loadable from 'react-loadable';
    
    const LoadableBar = Loadable({
      loader: () => import('react组件模块路径'),
      loading() {
        return <div>Loading...</div>
      }
    });
    
    class MyComponent extends React.Component {
      render() {
        return <LoadableBar/>;
      }
    }
    

    多页面多入口打包

    修改webpack.config.js如下

    ...
    entry: {
        // 把html 加入 entry。目的是修改html文件也能hot reload。
        // 不要在生产环境这么做。因为这会导致 chunk 文件包含了无用的 html 片段。
        page0: ['./src/pages/page0/index.js','./src/template/page0.html'],
        page1: './src/pages/page1/index.js',
    },
    plugins: [
        new HtmlWebPackPlugin({
            template: "./src/template/page0.html",
            filename: "./page0.html",
            chunksSortMode: 'none',
            chunks: ["page0"],
        }),
        new HtmlWebPackPlugin({
            template: "./src/template/page1.html",
            filename: "./page1.html",
            chunksSortMode: 'none',
            chunks: ["page1"],
        }),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
    ],  
    ...
    

    对应文件存放目录结构修改如图


    文件存放目录结构

    第三方库和业务代码分开打包

    基本策略是:

    1. 提取样式文件
    2. 分离公共文件(运行时,node_modules,业务的共同依赖)
    3. 懒加载大文件
      react-loadable
    简单分离公共文件和业务文件
    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    name: 'common',
                    priority: 10,
                    chunks: 'initial'
                }
            }
        }
    }
    
    分离业务文件,node_modules,业务的共同依赖,webpack运行时
    runtimeChunk: {
        name: 'manifest'
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    name: "vendors",
                    chunks: "all"
                },
                commons: {
                    chunks: "all",
                    name: 'commons',
                    /**
                     * minSize 默认为 30000
                     * 想要使代码拆分真的按照我们的设置来
                     * 需要减小 minSize
                     */
                    minSize: 0,
                    // 至少为两个 chunks 的公用代码
                    minChunks: 2
                }
            }
        }
    }
    

    这里打包出来的文件有vendros.js(node_modules),commons.js(业务的共同依赖),manifest.js(webpack运行时),业务文件

    手动指定业务的共同依赖
    entry: {
        // html可实时刷新修改
        page0: ['./src/pages/page0/index.js', './src/template/page0.html'],
        page1: './src/pages/page1/index.js',
        page2: './src/pages/page2/index.js',
        pageCommon: ['./src/common/page0-1.js', './src/common/page0-2.js'],
    },
    optimization: {
        runtimeChunk: {
            name: 'manifest'
        },
        splitChunks: {
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    name: "vendors",
                    chunks: "all"
                },
            }
        }
    },
    plugins: [
        new HtmlWebPackPlugin({
            template: "./src/template/page0.html",
            filename: "./page0.html",
            chunksSortMode: 'none',
            chunks: ["page0", "pageCommon", "vendors","manifest"],
        }),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
    ],
    

    手动指定共同依赖后,就不要再让webpack自动分析共同依赖,否则手动的共同依赖打包出来不生效。

    参考

    https://www.valentinog.com/blog/webpack-4-tutorial/
    https://github.com/fenivana/webpack-and-spa-guide
    https://segmentfault.com/a/1190000014685887

    相关文章

      网友评论

      本文标题:webpack4入门

      本文链接:https://www.haomeiwen.com/subject/bhemfftx.html