webpack4 开发环境搭建
npm 初始化项目
yarn init
安装webpack依赖
yarn add webpack webpack-dev-server webpack-cli @webpack-cli/init --dev
webpack 初始化
npx webpack-cli init
? Will your application have multiple bundles? Yes
? Type the names you want for your modules (entry files), separated by comma [example: app,vendor] app
? What is the location of "app"? [example: ./src/app] ./src/app
? Which folder will your generated bundles be in? [default: dist]: dist
? Will you be using ES2015? Yes
? Will you use one of the below CSS solutions? SASS
yarn add v1.12.1
添加编译插件
## 二选一
## 1. class 写法 向下兼容
yarn add @babel/plugin-proposal-class-properties --dev
## 2. babel 支持 import
## yarn add @babel/plugin-syntax-dynamic-import --dev
yarn add @babel/preset-env @babel/core cross-env --dev
安装loader
yarn add html-withimg-loader url-loader file-loader style-loader postcss-loader --dev
插件安装
yarn add mini-css-extract-plugin uglifyjs-webpack-plugin clean-webpack-plugin copy-webpack-plugin extract-css html-webpack-plugin --dev
安装webpack-chain
yarn add webpack-chain --dev
此处webpack-chain为5.0.1版本,是针对webpack 4维护的,需特别注意
github地址:webpack-chain
创建webpack.config.js
const path = require('path');
const isProd = process.env.NODE_ENV === 'production';
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const WebpackChain = require('webpack-chain');
const config = new WebpackChain();
config.when(isProd,config=>{
config.entry('index').add('./src/index.js');
}).when(!isProd,config=>{
config.entry('index').add('./src/index.js');
})
// Modify output settings
.output
.path(path.join(__dirname, "dist")).filename('[name].js').end()
.when(isProd, config => {
config.mode('production');
}).when(!isProd,config=>{
config.mode('development').devtool('source-map');
}).end();
/**
* module
*/
config
.module
.rule("compile")
.test(/\.js$/)
.include.add(path.join(__dirname,'src')).end()
.exclude.add(/node_modules/).end()
.use('babel').loader("babel-loader")
.options({
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-class-properties']
});
config.module
.rule('images')
.test(/\.(png|jpg|jpeg|gif)/)
.use('url-loader')
.loader('url-loader')
.options({
limit: 1 * 1024,
name: path.posix.join("images","[name].[ext]")
})
// do not base64-inline SVGs.
// https://github.com/facebookincubator/create-react-app/pull/1180
config.module
.rule('svg')
.test(/\.(svg)(\?.*)?$/)
.use('url-loader')
.loader('url-loader')
.options({
limit: 1024 * 3,//30kb
fallback: 'file-loader'
})
config.module
.rule("fonts")
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
.use('url-loader')
.loader('url-loader')
.options({
limit: 10000,
fallback: {
loader: 'file-loader',
options: {
name: path.posix.join("fonts","[name].[ext]")
}
}
});
config.when(isProd,config=>{
config.module.rule("css").test(/\.(sa|sc|c)ss$/)
.use("style").loader(MiniCssExtractPlugin.loader);
}).when(!isProd,config=>{
config.module.rule("css").test(/\.(sa|sc|c)ss$/)
.use("style-loader").loader("style-loader");
});
config.module.rule("css").test(/\.(sa|sc|c)ss$/)
.use('css').loader("css-loader").end()
.use('postcss-loader').loader('postcss-loader');
config.module.rule("scss").test(/\.(sa|sc)ss$/).use("sass-loader").loader("sass-loader");
config.module.rule("lass").test(/\.less$/).use("less-loader").loader("less-loader");
//config.module.rule("html").test(/\.(htm|html)$/i).use("html").loader('html-withimg-loader');
/**
* plugin
*/
config.when(isProd,config=>{
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require("copy-webpack-plugin");
config.plugin("clear").use(new CleanWebpackPlugin([path.join(__dirname, 'dist')]));
config.optimization.splitChunks({
cacheGroups: {
commons: {
chunks: "initial",
name: "common",
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0, // This is example is too small to create commons chunks
reuseExistingChunk: true // 可设置是否重用该chunk(查看源码没有发现默认值)
}
}
});
config.plugin("js").use(new UglifyJSPlugin({}));
config.plugin('extract-css')
.use(MiniCssExtractPlugin, [{
filename: "css/[name].css",
chunkFilename: "css/[name].css"
}]);
// config.plugin('copy').use(new CopyWebpackPlugin([
// {
// from:"./src/sass",
// }
// ]))
})
const HtmlWebpackPlugin = require('html-webpack-plugin');
config.plugin("html").use(HtmlWebpackPlugin, [{
/*
template 参数指定入口 html 文件路径,插件会把这个文件交给 webpack 去编译,
webpack 按照正常流程,找到 loaders 中 test 条件匹配的 loader 来编译,那么这里 html-loader 就是匹配的 loader
html-loader 编译后产生的字符串,会由 html-webpack-plugin 储存为 html 文件到输出目录,默认文件名为 index.html
可以通过 filename 参数指定输出的文件名
html-webpack-plugin 也可以不指定 template 参数,它会使用默认的 html 模板。
*/
template: "./public/index.html",
filename:"index.html",
/*
因为和 webpack 4 的兼容性问题,chunksSortMode 参数需要设置为 none
https://github.com/jantimon/html-webpack-plugin/issues/870
*/
chunksSortMode: 'none',
xhtml: true,
minify: {
collapseWhitespace: false, //删除空格,但是不会删除SCRIPT、style和textarea中的空格
conservativeCollapse: false, //删除空格,总是保留一个空格
removeAttributeQuotes: false, //删除引号,删除不需要引号的值
useShortDoctype: false, //使用短的文档类型
removeComments: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
}
}]);
config.when(isProd,config=>{
}).when(!isProd,config=>{
config.devServer.host('localhost').port(8080).open(process.os === 'darwin');
})
config.resolve.alias.set("@",path.join(__dirname,"src"));
// Export the completed configuration object to be consumed by webpack
module.exports = config.toConfig();
添加启动脚本
修改package.json文件中scripts节点,加入如下配置:
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack"
}
创建postcss.config.js
module.exports = {
plugins: {
autoprefixer: {
"browsers": [
"ie >= 9",
"ff >= 30",
"chrome >= 34",
"safari >= 7",
"opera >= 23"
]
}
}
}
创建src/index.js
export default class demo {
constructor(){
console.log("init");
}
}
创建example/index.js
import Demo from "../src/index";
const demo = new Demo();
根目录创建index.html
启动
yarn run dev