- next.js 只有服务端使用的包需要做单独处理,无需打包到项目中,可以使用@zeit/next-bundle-analyzer观察代码。
- Router.beforePopState() 截断Router操作的设置只有在客户端生效(需在componentDidMount中设置)且进入此函数中的方法只有Router栈中有值的时候才可以!
- next.js 中设置绝对路径的方法是在next.config.js中wepack方法中的config参数增加配置。
- next.js 中配置自定义接口可以使用自定义启动参数,创建 server.js 通过 node server.js 启动。
- next.js 支持IE11和各主流浏览器 IE11以内的IE版本不支持。
- Link 标签passHref属性可以强制给子元素传递href属性,有利于SEO优化。
- windows 不支持 NODE_ENV=development的设置方式 导入 cross-env 然后运行时在前面添加 cross-env 即可解决。
- webpack 配置自定义的时候覆盖配置需要继承本有的配置,否则会使 next 解析错误(analysis error)。
module.exports = { // ... other next.js config return { webpack: config => { config.resolve.alias = { ...(config.resolve.alias || {}), // custom webpack aliases } return config } } }
- null-loader 加载器的一个用途是关闭依赖项导入的模块。 例如,你的项目依赖于导入你不需要的polyfill的ES6库,因这里删除它将导致不会丢失功能。 测试polyfill的路径,它将不包含在你的包中。
- next.js 引入antd @zeit/next-css babel-plugin-import 按需加载无法正确编译css文件需要在next.config.js中配置服务端渲染方可。
const withCss = require('@zeit/next-css') module.exports = withCss({ webpack: (config, { isServer }) => { if (isServer) { const antStyles = /antd\/.*?\/style\/css.*?/ const origExternals = [...config.externals] config.externals = [ (context, request, callback) => { if (request.match(antStyles)) return callback() if (typeof origExternals[0] === 'function') { origExternals[0](context, request, callback) } else { callback() } }, ...(typeof origExternals[0] === 'function' ? [] : origExternals), ] config.module.rules.unshift({ test: antStyles, use: 'null-loader', }) } return config }, })
- next.js 引入@zeit/less需要将antd的按需加载style改为true。
- postCss/postCss-use 使用方法:
module.exports = { plugins: [ require('postcss-use')({ // allow autoprefixer modules: [ 'autoprefixer' ] }) ] }
- analysis && antd 3.x.x version icon 异步加载(next配置方案) && moment 语言包打包优化。
moment 语言包使用 webpack.IgnorePlugin 会把所有语言过滤掉,所以需要使用 webpack.ContextReplacementPlugin 来指定打包筛选方案,然后单独引入所需moment语言包即可!const webpack = require('webpack') const withSass = require('@zeit/next-sass'); const withBundleAnalyzer = require("@zeit/next-bundle-analyzer") module.exports = withBundleAnalyzer(withSass({ analyzeServer: ["server", "both"].includes(process.env.BUNDLE_ANALYZE), analyzeBrowser: ["browser", "both"].includes(process.env.BUNDLE_ANALYZE), bundleAnalyzerConfig: { server: { analyzerMode: 'static', reportFilename: '../../bundles/server.html' }, browser: { analyzerMode: 'static', reportFilename: '../bundles/client.html' } }, webpack: (config, { dev }) => { config.module.rules.push( { test: /\.(ttf|eot|svg|png|jpg|gif|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader', options: { name: '../../../[path][name].[ext]' } }, { test: /\.(css|scss)/, loader: 'emit-file-loader', options: { name: 'dist/[path][name].[ext]' } }, { test: /\.css$/, use: ['babel-loader', 'raw-loader', 'postcss-loader'] } //, { // test: /\.s(a|c)ss$/, // use: ['babel-loader', 'raw-loader', 'postcss-loader', // { // loader: 'sass-loader', // options: { // includePaths: ['styles', 'node_modules'] // .map((d) => path.join(__dirname, d)) // .map((g) => glob.sync(g)) // .reduce((a, c) => a.concat(c), []) // } // } // ] // } ) !dev && config.module.rules.push({ loader:'webpack-ant-icon-loader', enforce: 'pre', options:{ chunkName:'antd-icons' }, include: [ require.resolve('@ant-design/icons/lib/dist.js') ] }) !dev && config.plugins.push( // 阻止生成与正则表达式或过滤器函数匹配的模块import或require调用 // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // 引入未知包的时候webpack会推断出directory的包,然后全部打包进入bundle,此条配置允许覆盖推断信息,更加精确的配置打包数据 new webpack.ContextReplacementPlugin( /moment[\\\/]locale$/, /^\.\/(th)\.js$/ ) // 加到next/webpack.js配置中 // new webpack.optimize.CommonsChunkPlugin({ // // name: 'icons', // // filename: 'icons.js', // minChunks: function (module, count) { // if (dev || (module.resource && module.resource.includes('icons'))) { // return false; // } // } // }), ) return config }, // exportPathMap: function (defaultPathMap) { // return { // '/': { page: '/' }, // } // } }))
- 针对低版本next使用的webpack3配置中使用webpack-icons-loader需要单独配置以及处理export之后的文件索引,方案为:
var fs = require('fs') var path = require('path') function editWebpack (srcPath) { let prefix = path.extname(srcPath) // 过滤除js和html的文件 if (prefix === '.js') { const data = fs.readFileSync(srcPath, 'utf8'); let line = data.split('\n') let len = line.length let newLines = '' let isEdit = false for (let i = 0; i < len; i++) { if (i > 347 && i < 350) { let isFind = ~line[i].indexOf('(dev)') !isEdit && (isEdit = isFind) line[i] = isFind ? ' if (dev || (module.resource && module.resource.includes(\'icons\') && count >= 0)) {' : line[i] } newLines += line[i] + (i !== len - 1 ? '\n' : '') } fs.writeFileSync(srcPath, newLines, 'utf8'); isEdit && console.log('webpack update success:' + srcPath + '\n') } } function editIcons (srcPath, tarPath) { let prefix = path.extname(srcPath) // 过滤除js和html的文件 if (prefix === '.js') { const data = fs.readFileSync(srcPath, 'utf8'); fs.writeFileSync(tarPath, data, 'utf8') console.log('@ant-design update success:' + tarPath + '\n') } } editWebpack('./node_modules/next/dist/server/build/webpack.js') editIcons('./static/font/dist.js', './node_modules/@ant-design/icons/lib/dist.js')
var fs = require('fs') var path = require('path') function findFolder (srcDir, tarDir) { // 读取当前路径下的所有目录和文件,返回字符串数组 fs.readdir(srcDir, function (err, files) { files.forEach(function (file) { if (!~file.indexOf('antd-icons')) return var srcPath = path.join(srcDir, file) var tarPath = path.join(tarDir, file) fs.stat(srcPath, function (err, stats) { !stats.isDirectory() && copyFile(srcPath, tarPath) }) }) }) } function copyFile(srcPath, tarPath) { // 创建字节读取流 var rs = fs.createReadStream(srcPath) rs.on('error', function (err) { if (err) { console.log('read error', srcPath) } }) // 创建字节写入流 var ws = fs.createWriteStream(tarPath) ws.on('error', function (err) { if (err) { console.log('write error', tarPath) } }) ws.on('close', function (ex) { }) rs.pipe(ws) console.log('ant-icons move success:' + srcPath + '\n') } findFolder('./.next/', './out/_next/webpack/')