FunnyLiu / webpackDemo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

webpack 相关 demo

启动 npm run start01

打包 npm run build01

入口文件 demo01_entry

module.exports = {
  entry: "./main.js",
  output: {
    filename: "./bundle.js"
  }
};

多入口文件 demo02_multiEntry

module.exports = {
  entry: {
    bundle1: "./main1.js",
    bundle2: "./main2.js"
  },
  output: {
    filename: "[name].js"
  }
};

babel-loader 引入 jsx demo03_babelLoader

module.exports = {
  entry: "./main.jsx",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react"]
          }
        }
      }
    ]
  }
};

cssloader demo04cssLoader

cssloader 用来解析 require 的 css 文件,而 style-loader 用来将样式通过 style 的方式加入 html

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      }
    ]
  }
};

urlloader demo05_imageLoader

urlloader 用于解析 require 进的图片类型。

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.(png|jpg)$/,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 8192
            }
          }
        ]
      }
    ]
  }
};

cssmodule demo06_cssModule

css 模块化引入

main.jsx

var React = require("react");
var ReactDOM = require("react-dom");
//模块化的css,引入并使用
var style = require("./app.css");

ReactDOM.render(
  <div>
    <h1 className={style.h1}>Hello World</h1>
    <h2 className="h2">Hello Webpack</h2>
  </div>,
  document.getElementById("example")
);

app.css

.h1 {
  color: red;
}

/* 全局通用的需要额外标识 */
:global(.h2) {
  color: blue;
}

webpack.config.js

module.exports = {
  entry: "./main.jsx",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react"]
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: "style-loader"
          },
          {
            loader: "css-loader",
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }
};

uglifyJS demo07_uglify

使用 uglify 插件编译 js

var webpack = require("webpack");
var UglifyJsPlugin = require("uglifyjs-webpack-plugin");

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  plugins: [new UglifyJsPlugin()]
};

打包 html demo08_browser

通过 html-webpack-plugin 将 html 进行打包出来,通过 open-browser-webpack-plugin 在启动 webpack 时新开浏览器。

var HtmlwebpackPlugin = require("html-webpack-plugin");
var OpenBrowserPlugin = require("open-browser-webpack-plugin");

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  plugins: [
    new HtmlwebpackPlugin({
      title: "Webpack-demos",
      filename: "index.html"
    }),
    new OpenBrowserPlugin({
      url: "http://localhost:8081"
    })
  ]
};

环境变量 demo09_environmentFlag

通过 cross-env,在启动时设置环境变量,在代码层通过环境变量控制逻辑

package.json

{
  "start09": "cd demo09_environmentFlag && cross-env DEBUG=true node server"
}

main.js

document.write("<h1>Hello World</h1>");

//环境标识
if (__DEV__) {
  document.write(new Date());
}

webpack.config.js

var webpack = require("webpack");

//定义一个webpack插件,传递字符串__DEV__
var devFlagPlugin = new webpack.DefinePlugin({
  __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || "false"))
});

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  plugins: [devFlagPlugin]
};

动态加载 demo10_dynamicImport

通过 require.ensure 或 import,根据用户交互行为,动态加载模块 bundle。

main.js

let ensureNode = document.querySelector("#j-ensure");
let importNode = document.querySelector("#j-import");
ensureNode.addEventListener(
  "click",
  () => {
    //通过requie.ensure来动态加载其他js文件
    require.ensure(["./a"], function(require) {
      var content = require("./a");
      //异步加载的js
      document.open();
      document.write("<h1>" + content + "</h1>");
      document.close();
    });
  },
  false
);

importNode.addEventListener(
  "click",
  () => {
    //通过import的方式调用热加载,指定webpackChunkName后加载文件从0.bundle.js变为a.bundle.js
    //import为promise的方式
    return import(/* webpackChunkName: "a" */ "./a")
      .then(({ default: _ }) => {
        //异步加载的js
        document.open();
        document.write("<h1>" + _ + "</h1>");
        document.close();
      })
      .catch(error => "An error occurred while loading the conntent");
  },
  false
);

webpack.config.js

module.exports = {
  mode: "development",
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  }
};

bundleLoader 来动态引入 demo11_bundleLoader

使用 bundleLoader 来动态引入文件

main.js

import bundle from "./a.bundle.js";

let loaderNode = document.querySelector("#j-loader");
loaderNode.addEventListener(
  "click",
  () => {
    bundle(file => {
      document.open();
      document.write("<h1>" + file + "</h1>");
      document.close();
    });
  },
  false
);

webpack.config.js

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.bundle\.js$/,
        use: {
          loader: "bundle-loader",
          options: {
            lazy: true
          }
        }
      }
    ]
  }
};

公共 chunk demo12_commonChunk

使用 splitChunks 的方式,配置在多入口 entry 中的文件,共同依赖项抽出。

module.exports = {
  entry: {
    bundle1: "./main1.jsx",
    bundle2: "./main2.jsx"
  },
  output: {
    filename: "[name].js"
  },
  module: {
    rules: [
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react"]
          }
        }
      }
    ]
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          name: "commons",
          chunks: "initial",
          minChunks: 2
        }
      }
    }
  }
};

全局别名 demo13_externals

通过 externals 给第三方库挂载在全局的别名进行映射。

main.js

import $ from "jquery";

$("#j-dom").show();

webpack.config.js

module.exports = {
  mode: "development",
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  //全局变量映射,import 时的 from 会查找
  externals: {
    jquery: "jQuery"
  }
};

带 hash 的 chunk demo14_chunkHash

生成文件名使用hash的方式

var path = require("path");
module.exports = {
  entry: {
    main: "./main.js"
  },
  optimization: {
    runtimeChunk: true
  },
  output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].[chunkhash].js",
    chunkFilename: "[name].[chunkhash].js"
  }
};

热更新 by eppress 中间件 demo15_HMR_express

使用express的中间件webpack-hot-middleware,来实现热更新

main1.js

import css from './app.css';
console.warn('this is console1');
if (module.hot) {
    module.hot.accept();
}

webpack.config.js

const  webpack = require('webpack') 

module.exports = {
  entry: {
    bundle1: ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000','./main1.js'],
    bundle2: ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000','./main2.js']
  },
  output: {
    filename: '[name].js'
  },
  module: {
    rules:[
      {
        test: /\.css$/,
        use: ['style-loader','css-loader']
      },
    ]
  },
  plugins:[
    new webpack.HotModuleReplacementPlugin()
  ]
};

启动的server.js

    
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware');
const WebpackConfig = require(`./webpack.config`)

const app = express()
const compiler = webpack(WebpackConfig)


app.use(webpackDevMiddleware(compiler, {
  stats: {
    colors: true,
    chunks: false
  }
}))

//启用模块热更新
app.use(webpackHotMiddleware(compiler, {
  path: '/__webpack_hmr',
  heartbeat: 10 * 1000
}));

app.use(express.static(__dirname))

const port = process.env.PORT || 8081
module.exports = app.listen(port, () => {
  console.log(`Server listening on http://localhost:${port}, Ctrl+C to stop`)
})

热更新 by webpack-dev-server cli demo16_HMR_cli

不需要啥额外的配置,只需要启动server时设置一定的参数就好了。

package.json

    "start16": "cd demo16_HMR_cli && webpack-dev-server --inline --watch --hot",

main.js

    "start16": "cd demo16_HMR_cli && webpack-dev-server --inline --watch --hot",

webpack.config.js

module.exports = {
  entry: {
    bundle1: './main1.js',
    bundle2: './main2.js'
  },
  output: {
    filename: '[name].js'
  },
  module: {
    rules:[
      {
        test: /\.css$/,
        use: ['style-loader','css-loader']
      },
    ]
  }
};

热更新 by webpack-dev-server api demo17_HMR_api

还是通过webpack-dev-server,但是不是cli而是api,来启用热更新

main1.js

import css from './app.css';
console.warn('this is console2');
if (module.hot) {
    module.hot.accept();
}

server.js

const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');

const config = require('./webpack.config.js');
const options = {
    hot: true,
    host: 'localhost',
    stats: {
        colors: true
    }
};
//设置配置
webpackDevServer.addDevServerEntrypoints(config, options);

var compiler = webpack(config);
var server = new webpackDevServer(compiler, options);

server.listen(8081, 'localhost', () => {
    console.log('dev server listening on port 8081');
});

单纯的html和js文件 by webpack-dev-server和html-webpack-plugin demo18_html

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  devtool: 'inline-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve('./public/index.html'),
      title: 'development'
    })
  ],
};

使用http-mockjs来mock接口 by demo19_mock

const mocker = require('http-mockjs').default

module.exports = {
  mode: 'development',
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  devtool: 'inline-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve('./public/index.html'),
      title: 'development'
    })
  ],
  devServer:{
    port:'8002',
    before:(app)=>{
      mocker(app)
    }
  }
};

使用devServer的proxy功能来CORS跨域 by demo20_proxy

将本地/api下的路径代理到localhost:3000上。 比如localhost:8002/api/get --> localhost:3000/get

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  devtool: 'inline-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve('./public/index.html'),
      title: 'development'
    })
  ],
  devServer:{
      proxy:{
          '/api':{
              target:'http://localhost:3000',
              pathRewrite:{'^/api':''},
              changeOrigin:true,
              secure:false
          }
      }
  }
};

使用SRI来判断script内容是否一致,从而防止CDN劫持问题 by demo21_SRI

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const SriPlugin = require('webpack-subresource-integrity')

module.exports = {
  mode: 'development',
  entry: {
    app: './src/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  devtool: 'inline-source-map',
  plugins: [
    new SriPlugin({
      hashFuncNames:['sha256']
    }),
    new HtmlWebpackPlugin({
      template: path.resolve('./public/index.html'),
      title: 'development'
    })
  ],
};

使用less来管理页面样式 by demo22_less

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./main.js",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve("./index.html"),
      title: "development"
    })
  ]
};

只需要在js中引入less即可:

import './index.less'

使用less,通过css module来管理react组件 by demo23_less_cssmodule

需要对css-loader进行额外配置:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./main.jsx",
  output: {
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              modules: true,
              localIdentName: '[local]___[hash:base64:5]'
            }
          },
          "less-loader"
        ]
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react"]
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve("./index.html"),
      title: "development"
    })
  ]
};

组件内直接引用less即可:

import React from 'react'
import styles from './head.less'

const Head = ()=>{
    console.log(styles.head)
    return (
        <div className={styles.head}>This is head</div>
    )
}
export default Head

多个html分别引入不同的js,通过chunks对应 by demo24_multi_js_html

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: {
    page1: "./page1/script/main.js",
    page2: "./page2/script/main2.js"
  },
  output: {
    filename: "./[name]/build/bundle.js"
  },
  plugins: [
    new HtmlWebpackPlugin({
      chunks: ["page1"],
      filename: "./page1/build/index.html"
    }),
    new HtmlWebpackPlugin({
      chunks: ["page2"],
      filename: "./page2/build/index.html"
    })
  ]
};

静态资源走cdn而不是本地路径,通过output的publicPath配置,by demo25_cdn

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    app: './main.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    //use publicPath to set script'src includes cdn url
    publicPath: 'https://cdn.example.com/assets/'
  },
  devtool: 'inline-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve('./index.html'),
      title: 'development'
    })
  ],
};

Vue项目配合codesplit功能 demo026_vueInit

const webpack = require('webpack');
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const config = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  },
  resolve: {
    extensions: [
      '.js',
      '.vue'
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve('./index.html'),
      title: 'development'
    })
  ],
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

module.exports = config;

hard-source-webpack-plugin插件,做缓存优化构建速度的 demo27_hardSourcePlugin

About


Languages

Language:JavaScript 80.4%Language:HTML 14.2%Language:Vue 4.7%Language:CSS 0.6%Language:Less 0.1%