webpack 简单配置

977 阅读3分钟

在浏览器中运行 JavaScript 有两种方法。第一种方式,引用一些脚本来存放每个功能;此解决方案很难扩展,因为加载太多脚本会导致网络瓶颈。第二种方式,使用一个包含所有项目代码的大型 .js 文件,但是这会导致作用域、文件大小、可读性和可维护性方面的问题。为什么选择 webpack

社区里面已经有非常多关于webpack使用教程和原理分析,但始终不如自己亲自尝试,一点一点建设起来理解的更快。

我目前浅显的理解(有错及时纠正我):
webpack就是一个工厂,里面会有一条流水线,流水线上会有一条或多条传送带,入口模块就是一个产品,loader先对产品进行翻译,plugin就是一个工具,监听着流水线上传送带运送的位置(也就是webpack提供的hook),当传送带开始运作(启动webpack)的时候,每个模块就会进入传送带,当传送带将模块传送到某个点时就会通知对应监听的工具并将模块暂时交由它处理,处理完就由传送带继续往下传送,直到终点,然后就可以进行装货(输出)了。
可以简单的理解为: entry -> loader -> plugins -> output , 中间还会去读取其他配置例如:resolver/mode/optimization等等。

项目初始化(建议安装最新稳定版node和npm):

    npm init

安装:

    npm i -S webpack
    npm i -S webpack-cli

webpack的配置文件(webpack.config.js)

 entry          模块入口起点
 output         模块输出
 loader         用于对入口模块的源代码进行转换
 plugins        插件
 resolver       设置模块如何被解析
 devServer      本地服务
 mode           模式,分为开发模式和生产模式,默认为production
 
 // 以下可以都是属于优化选项,webpack有默认配置
 optimization   优化,根据mode执行不同的优化
 devtool        控制是否生成source map
 ...
 

简单配置:

module.exports = {
    // production(默认)/development/none
    /**
     * 可以在配置中指定,也可以在CLI参数中传递:webpack --mode=development
     */
    mode: 'production',
    // 上下文环境, 默认为当前目录
    content: path.resolve(__dirname),
    // MPA 多页应用
    entry: {
        index: 'src/js/index.js',
        about: 'src/js/about'
    },
    output: {
      filename: '[name].js',
      path: path.resolve(__dirname, 'dist')
    },
    // 模块匹配和处理 大部分都是做编译处理
    module: {
        rules: [
            {
                test: /\.js$/,
                // use 是 loader的别名
                use: ['babel-loader'],
                // 排除特定条件
                exclude: '/node_modules/'
            },
            {
                test: /\.css$/,
                use: ['style-loader','css-loader'] // 顺序是不可以搞错的
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: ['file-loader']
            }
            //...
        ]
    },
    plugins: [
        // 多页应用则实例多个HtmlWebpackPlugin
        // 创建HTML文件
        new HtmlWebpackPlugin({
                title   : 'index',
                filename: 'index.html',
                inject  : false,
        }),
        new HtmlWebpackPlugin({
                title   : 'about',
                filename: 'about.html',
                inject  : false,
        }),
        // 引入热更新插件,辅助devServer 使页面刷新更快
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        // 静态文件目录 建议与output.path一致
        contentBase: path.join(__dirname, 'dist'),
        // 是否启用压缩
        compress: true,
        // 启用服务的地址
        host:'localhost',
        // 启用服务的端口号
        port: 9527,
        // 自动打开页面
        open:true
    },
    optimization: {
        // 对动态导入模块做配置 
        splitChunks: {
            // 匹配同步和异步模块
            chunks: 'all',
            // 模块被复用的最小次数
            minChunks: 2,
            // 生成块的最小大小 bytes为单位
            minSize: 30000, 
            
        }
    },
    /**
     * 是否生成 source-map
     * development 下建议 eval-source-map, 重新构建速度会比较快并且行数能够正确的映射
     * production  下建议 none, 不生成,会大大缩小编译后的文件大小,如果需要则使用 'source-map',会单独生成一个文件 
     */
    // 可以使用 SourceMapDevToolPlugin 进行更细粒度的配置,但不要同时使用,否则会同时运行
    devtool: 'eval-source-map' 
}

entry

    // SPA 单页应用
    entey: 'src/js/*.js'
    // MPA 多页应用
    entry: getEntry('./src/js')
    const glob = require('glob');
    const path = require('path');
    function getEntry(filesPath) {
      const files = glob.sync(filesPath);
      let entries = {},
          basename,
          extname;
      files.forEach( file => {
        extname = path.extname(file);//返回指定文件名的扩展名称
        /**
         * path.basename(p, [ext])
         * 返回指定的文件名,返回结果可排除[ext]后缀字符串
         * path.basename('/foo/bar/baz/asdf/quux.html', '.html') => quux
         */
        basename = path.basename(file, extname);
        entries[basename] = file;
      });
      return entries
    }
    module.exports = getEntry;

有错及时纠正,其他配置下回继续...