初始化打包公共npm包,加快打包速度javascript
npm run dll 或者 yarn dll
开发环境css
npm run dev 或者 yarn dev
生产环境打包html
npm run build 或者 yarn build
首先附上官方的文档html5
github地址java
https://github.com/xiaopingzh...
会不定时更新,若是以为有帮助到你,给个Star当作鼓励可好。node
. ├── README.md ├── build │ ├── webpack.dev.conf.js │ ├── webpack.dll.conf.js │ └── webpack.prod.conf.js ├── dist ├── dll ├── manifest.json ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── components │ │ ├── Bread │ │ │ └── Bread.js │ │ └── SiderBar │ │ └── SiderBar.js │ ├── index.js │ ├── layouts │ │ └── BasicLayout.js │ ├── pages │ │ ├── Counter │ │ │ └── Counter.js │ │ └── Home │ │ └── Home.js │ ├── redux │ │ ├── actions │ │ │ └── counter.js │ │ ├── reducer.js │ │ ├── reducers │ │ │ └── counter.js │ │ └── store.js │ ├── request │ │ └── request.js │ ├── router │ │ └── Router.js │ └── util │ └── loadable.js └── yarn.lock
webpack
,再安装webpack-cli
>npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help json` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (webpack4) version: (1.0.0) description: entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to /Users/xiaopingzhang/UCloud/webpack4/package.json: { "name": "webpack4", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } Is this OK? (yes) yes
初始化以后按照提示一步步往下就能够了,能够输入该项目的描述等等信息。一开始也没有关系,后面也还能够更改。react
下一步 本地安装webpack
,再安装webpack-cli
webpack
npm install webpack webpack-cli --save-dev
==--save-dev
是你开发时候依赖的东西,--save
是你发布以后还依赖的东西。==ios
>npm install webpack webpack-cli --save-dev > fsevents@1.2.7 install /Users/xiaopingzhang/UCloud/webpack4/node_modules/fsevents > node install node-pre-gyp WARN Using needle for node-pre-gyp https download [fsevents] Success: "/Users/xiaopingzhang/UCloud/webpack4/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" is installed via remote > webpack-cli@3.2.1 postinstall /Users/xiaopingzhang/UCloud/webpack4/node_modules/webpack-cli > lightercollective *** Thank you for using webpack-cli! *** Please consider donating to our open collective to help us maintain this package. https://opencollective.com/webpack/donate *** npm WARN webpack4@1.0.0 No description npm WARN webpack4@1.0.0 No repository field. + webpack-cli@3.2.1 + webpack@4.29.0 added 458 packages from 239 contributors and audited 5208 packages in 18.624s found 0 vulnerabilities
安装好以后,也会显示安装的哪一个版本,通常安装没有啥问题。实在安装不成功,试一下全局安装。git
2.新建src
文件夹,入口的js
文件和html
文件。
. ├── index.html ├── package.json └── src └── index.js
index.js文件
const component = () => { let element = document.createElement("div"); element.innerHTML = "webpackworks"; return element; }; document.body.appendChild(component());
index.html
<!DOCTYPE html> <html> <head> <title>Start</title> </head> <body> <script src="./dist/main.js"></script> </body> </html>
3.学会使用webpack编译文件
输入 npx webpack
>npx webpack Hash: 9ad2a368debc9967c1f4 Version: webpack 4.29.0 Time: 269ms Built at: 2019-01-27 21:15:22 Asset Size Chunks Chunk Names main.js 1.01 KiB 0 [emitted] main Entrypoint main = main.js [0] ./src/index.js 218 bytes {0} [built] WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
再用浏览器打开index.html
,查看网页是否正常的显示了。
webpack 把入口文件 index.js
通过处理以后,生成 main.js
通过第一部分的尝试,已经初步了解webpack
的做用,这一部分经过配置文件进行相应的一些设置。
Babel 把用最新标准编写的 JavaScript 代码向下编译成能够在今天随处可用的版本。 这一过程叫作“源码到源码”编译, 也被称为转换编译。
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
新建babel配置文件.babelrc
{ "presets": [ "es2015", "react", "stage-0" ], "plugins": [] } //babel-core 调用Babel的API进行转码 //babel-loader //babel-preset-es2015 用于解析 ES6 //babel-preset-react 用于解析 JSX //babel-preset-stage-0 用于解析 ES7 提案
webpack.base.conf.js webpack.dev.conf.js webpack.prod.conf.js
分别是公共配置,开发配置,生产配置。
目前目录结构为
. ├── build │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── dist │ └── main.js ├── index.html ├── package.json └── src └── index.js
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
在 src 目录下新建.babelrc
{ "presets": [ [ "env", { "targets": { "browsers": [">1%", "last 3 versions"] } } ], "stage-2", "latest", "react" ], "plugins": [ "syntax-dynamic-import", "transform-class-properties", <!--[--> <!-- "import",--> <!-- {--> <!-- "libraryName": "antd",--> <!-- "libraryDirectory": "es",--> <!-- "style": true--> // "style": "css" //主题设置 <!-- }--> <!--]--> 不用antd 能够去掉 ] }
文件新增
{ test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, '../src') ], //包括 use: { loader: 'babel-loader' } },
npm install --save-dev style-loader css-loader
在配置文件里添加
{ test: /\.css$/, use: ["style-loader", "css-loader"] }
npm install --save-dev url-loader file-loader
在配置文件里添加
{ test: /\.(png|jpg|gif)$/, use: [ { loader: "url-loader", options: { limit: 8192 } } ] }
options limit:8192
意思是,小于等于8K的图片会被转成base64编码,直接插入HTML中,减小HTTP请求。
在这个踩了一个坑,记得安装 less
npm install --save-dev less-loader less
更改antd 默认主题设置须要,不用的话应该把相应的设置忽略便可。
{ test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS options: { modifyVars: { 'font-size-base': '12px', 'primary-color': '#0EA679' }, javascriptEnabled: true } } ] }
那么,像字体这样的其余资源如何处理呢?file-loader 和 url-loader 能够接收并加载任何文件,而后将其输出到构建目录。这就是说,咱们能够将它们用于任何类型的文件,包括字体。更新 webpack.config.js 来处理字体文件:
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ["file-loader"] }
HtmlWebpackPlugin做用是生成一个HTML模板。
HtmlWebpackPlugin简化了HTML文件的建立,以便为你的webpack包提供服务。这对于在文件名中包含每次会随着编译而发生变化哈希的 webpack bundle 尤为有用。
你可让插件为你生成一个HTML文件,使用lodash模板提供你本身的模板,或使用你本身的loader
首先须要安装插件:
npm install --save-dev html-webpack-plugin
在生产配置文件里添加
plugins: [ new HtmlWebpackPlugin({ template: 'public/index.html', title: 'title', // 更改HTML的title的内容 favicon: 'public/favicon.ico', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true, }, }),
在每次构建前清理 /dist 文件夹.
npm install clean-webpack-plugin --save-dev
new CleanWebpackPlugin(['../dist'])
https://webpack.docschina.org...
模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它容许在运行时更新各类模块,而无需进行彻底刷新。
有两种方式
"dev": "webpack --config build/webpack.dev.config.js --color --progress --hot"
import React from 'react'; import ReactDom from 'react-dom'; **if (module.hot) { module.hot.accept(); }** //增长
const webpack = require('webpack'); devServer: { hot: true } plugins:[ new webpack.HotModuleReplacementPlugin() ]
https://www.redux.org.cn/
官方文档先给上,一开始学的时候也觉得这个比较难,开始写就不会了。
网上看看例子,本身在coding一下就差很少了。
这边用到了一个中间件 redux-thunk
npm install --save redux-thunk
附上写的代码
注释的部分为生产环境使用。
为了方便debug代码,在控制台打印readux日志。
// import { createStore, applyMiddleware } from 'redux'; // import thunk from 'redux-thunk'; // import rootReducer from './reducer'; // const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); // const store = createStoreWithMiddleware(rootReducer); // export default store; // 打印操做日志,方便调试,生产环境能够去掉,用上面注释的配置。 import thunk from "redux-thunk"; // redux 做者开发的异步处理方案 能够在action 里传入 dispatch getState import { createLogger } from "redux-logger"; // 利用redux-logger打印日志 import { createStore, applyMiddleware } from "redux"; // 引入redux createStore、中间件及compose import { composeWithDevTools } from "redux-devtools-extension"; // devToolsEnhancer, import reducer from "./reducer"; // 引入reducers集合 // 调用日志打印方法 collapsed是让action折叠,看着舒服点 const loggerMiddleware = createLogger({ collapsed: true }); // 建立一个中间件集合 const middleware = [thunk, loggerMiddleware]; // 建立store const store = createStore( reducer, composeWithDevTools(applyMiddleware(...middleware)) ); export default store;
export const INCREMENT = 'counter/INCREMENT'; export const DECREMENT = 'counter/DECREMENT'; export const RESET = 'counter/RESET'; export function increment() { return { type: INCREMENT }; } export function decrement() { return { type: DECREMENT }; } export function reset() { return { type: RESET }; }
import { INCREMENT, DECREMENT, RESET } from '../actions/counter'; const initState = { count: 0, }; export default function reducer(state = initState, action) { switch (action.type) { case INCREMENT: return { count: state.count + 1, }; case DECREMENT: return { count: state.count - 1, }; case RESET: return { count: 0 }; default: return state; } }
import { combineReducers } from "redux"; import counter from "./reducers/counter"; export default combineReducers({ counter });
https://github.com/jamiebuild...
官方文档先附上
// 加载页面 import Loadable from 'react-loadable'; import React, { Component } from 'react'; import { Spin, Icon } from 'antd'; const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />; const antLong = ( <Icon type="loading" style={{ fontSize: 24, color: 'red' }} spin /> ); const antError = ( <Icon type="loading" style={{ fontSize: 24, color: 'red' }} spin /> ); export const Loading = props => { if (props.error) { return ( <Spin size="large" tip="加载错误 。。。" indicator={antError} style={{ position: 'absolute', color: 'red', top: '40%', left: '50%' }} /> ); } else if (props.timedOut) { return ( <Spin size="large" tip="加载超时 。。。" indicator={antLong} style={{ position: 'absolute', color: 'red', top: '40%', left: '50%' }} /> ); } else if (props.pastDelay) { return ( <Spin size="large" tip="Loading 。。。" indicator={antError} style={{ position: 'absolute', color: 'red', top: '40%', left: '50%' }} /> ); } else { return null; } }; export const importPath = ({ loader }) => { return Loadable({ loader, loading: Loading, delay: 200, timeout: 10000 }); };
在须要用到的地方引入这个文件就ok了。只是简单的写了一个例子,后续再完善吧。axios使用起来很简洁。
import axios from "axios"; import { message } from "antd"; import NProgress from "nprogress"; import "nprogress/nprogress.css"; // 拦截全部有请求与回复 // Add a request interceptor axios.interceptors.request.use( config => { NProgress.start(); return config; }, error => { message.error("请求错误,请重试"); return Promise.reject(error); } ); // Add a response interceptor axios.interceptors.response.use( response => { // NProgress.done(); // if (response.data.RetCode === 101) { // message.error(response.data.Message); // return response; // } // if (response.data.RetCode === 100) { // message.error(response.data.Message); // return response; // } return response; }, error => { message.error("请求错误,请重试"); NProgress.done(); return Promise.reject(error); } ); export default request;
plugins: [ // 处理html new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', title: '管理平台', favicon: 'public/favicon.ico', filename: 'index.html', hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), new CleanWebpackPlugin(['../dist'], { allowExternal: true }), new BundleAnalyzerPlugin(), new MiniCssExtractPlugin({ chunkFilename: '[chunkhash].css' }), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require('../dll/manifest.json') }), new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ]) ]
const HtmlWebpackPlugin = require('html-webpack-plugin'); new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', title: '管理平台', favicon: 'public/favicon.ico', filename: 'index.html', hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }),
const CopyWebpackPlugin = require('copy-webpack-plugin'); new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ])
const CleanWebpackPlugin = require('clean-webpack-plugin'); new CleanWebpackPlugin(['../dist'], { allowExternal: true })
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') .BundleAnalyzerPlugin; new BundleAnalyzerPlugin(),
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); new MiniCssExtractPlugin({ chunkFilename: '[chunkhash].css' })
const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const DIST_PATH = path.resolve(__dirname, '../dist'); //生产目录 const APP_PATH = path.resolve(__dirname, '../src'); //源文件目录 module.exports = { mode: 'development', entry: { index: './src/index.js' }, output: { path: DIST_PATH, //出口路径 filename: 'index.js', chunkFilename: 'js/[name].[chunkhash].js', //按需加载名称 // publicPath: "./" }, // 源错误检查 devtool: 'inline-source-map', //模块配置 module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, '../src'), path.resolve(__dirname, '../node_modules/antd/') ], //包括 use: { loader: 'babel-loader' } }, { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'] }, //更改antd主题设置 { test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS options: { modifyVars: { 'font-size-base': '12px', 'primary-color': '#0EA679' }, javascriptEnabled: true } } ] } ] }, //插件 plugins: [ new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', favicon: 'public/favicon.ico', title: '管理平台', overlay: true, minify: { html5: false }, hash: true }), // 热更新 new webpack.HotModuleReplacementPlugin(), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require('../dll/manifest.json') }), new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ]) ], // 热更新 devServer: { port: '3300', contentBase: DIST_PATH, historyApiFallback: true, hot: true, // 开启 https: false, compress: false, noInfo: true, open: true, proxy: { // '/': { // target: '', // changeOrigin: true, // secure: false, // }, } } };
const path = require('path'); const webpack = require('webpack'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const vendors = [ 'antd', 'axios', 'nprogress', 'react', 'react-dom', 'react-loadable', 'react-redux', 'react-router', 'react-router-dom', 'redux' ]; module.exports = { entry: { vendor: vendors }, output: { path: path.resolve(__dirname, '../dll'), filename: 'Dll.js', library: '[name]_[hash]' }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, '../dll', 'manifest.json'), name: '[name]_[hash]', context: __dirname }), new CleanWebpackPlugin(['../dll'], { allowExternal: true }) ] };
const path = require('path'); const webpack = require('webpack'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') .BundleAnalyzerPlugin; const DIST_PATH = path.resolve(__dirname, '../dist'); //生产目录 module.exports = { mode: 'production', entry: { index: './src/index.js' }, output: { path: DIST_PATH, //出口路径 filename: 'index.js', chunkFilename: '[name]_[hash].js', //按需加载名称 // publicPath: './' }, // 源错误检查 devtool: 'source-map', //模块配置 module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, '../src'), path.resolve(__dirname, '../node_modules/antd/') ], //包括 use: { loader: 'babel-loader' } }, { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] }, //更改antd主题设置 { test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' // translates CSS into CommonJS }, { loader: 'less-loader', // compiles Less to CSS options: { minimize: true, modifyVars: { 'font-size-base': '12px', 'primary-color': '#0EA679' }, javascriptEnabled: true } } ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'] } ] }, //插件 plugins: [ // 处理html new HtmlWebpackPlugin({ template: 'public/index.html', path: '../public/index.html', inject: 'body', title: '管理平台', favicon: 'public/favicon.ico', filename: 'index.html', hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), new CleanWebpackPlugin(['../dist'], { allowExternal: true }), new BundleAnalyzerPlugin(), new MiniCssExtractPlugin({ chunkFilename: '[chunkhash].css' }), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require('../dll/manifest.json') }), new CopyWebpackPlugin([ { from: 'dll/Dll.js', to: DIST_PATH } ]) ] // 热更新 };
ERROR in Path must be a string. Received undefined Child html-webpack-plugin for "index.html": 1 asset Entrypoint undefined = index.html
这个错误不影响打包结果,应该是版本问题致使。
https://github.com/jantimon/h...
写完才发现有些忘记记录了,会保持更新。
学习的过程当中也学习参考了其余优秀的博客和github,以及文档。
https://github.com/brickspert...https://github.com/NewPrototy...
https://github.com/axios/axios