I am using https://github.com/zeit/next.js/ and had a look at the examples:
https://github.com/zeit/next.js/tree/canary/examples/with-ant-design-less
https://github.com/zeit/next.js/tree/canary/examples/with-redux
https://github.com/zeit/next.js/tree/canary/examples/with-polyfills
I merged the three projects, so that I can use ant design and redux together with polyfill.
Works so far in Chrome, but it seems that the polyfills are not loaded correctly now.
My next.config.js looks like this:
/* eslint-disable */
const withLess = require("#zeit/next-less");
const lessToJS = require("less-vars-to-js");
const fs = require("fs");
const path = require("path");
// Where your antd-custom.less file lives
const themeVariables = lessToJS(
fs.readFileSync(path.resolve(__dirname, "./assets/antd-custom.less"), "utf8")
);
module.exports = withLess({
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables // make your antd custom effective
},
webpack: (config, {
isServer,
defaultLoaders
}) => {
const originalEntry = config.entry;
config.entry = async() => {
const entries = await originalEntry();
if (
entries["main.js"] &&
!entries["main.js"].includes("./polyfills.js")
) {
entries["main.js"].unshift("./polyfills.js");
}
return entries;
};
config.module.rules.push({
test: /\.scss$/,
use: [
defaultLoaders.babel,
{
loader: require("styled-jsx/webpack").loader,
options: {
type: "scoped",
javascriptEnabled: true
}
},
"sass-loader"
]
});
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/;
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;
}
});
My .eslintrc.js looks like this:
module.exports = {
extends: ["airbnb"],
env: {
browser: true
},
parser: "babel-eslint",
rules: {
indent: 0,
"comma-dangle": [
2,
{
arrays: "always-multiline",
objects: "always-multiline",
imports: "always-multiline",
exports: "always-multiline",
functions: "ignore"
}
],
"max-len": 1,
"arrow-parens": 0,
"import/no-named-as-default": 0,
"import/no-extraneous-dependencies": 0,
"no-nested-ternary": 0,
"no-use-before-define": 0,
"react/jsx-props-no-spreading": 0,
"react/prop-types": 1,
"react/no-array-index-key": 1,
"react/no-did-mount-set-state": 0,
"jsx-a11y/label-has-for": [
2,
{
components: ["Label"],
required: {
some: ["nesting", "id"]
},
allowChildren: true
}
],
"jsx-a11y/click-events-have-key-events": 1,
"jsx-a11y/no-noninteractive-element-interactions": 1,
"jsx-a11y/anchor-is-valid": 1,
"jsx-a11y/no-static-element-interactions": 1
}
};
My polyfills.js:
/* eslint no-extend-native: 0 */
// core-js comes with Next.js. So, you can import it like below
import includes from 'core-js/library/fn/string/virtual/includes';
import repeat from 'core-js/library/fn/string/virtual/repeat';
import assign from 'core-js/library/fn/object/assign';
// Add your polyfills (from IE10 is supported by default)
// This files runs at the very beginning (even before React and Next.js core)
String.prototype.includes = includes;
String.prototype.repeat = repeat;
Object.assign = assign;
In IE11 I get:
Object doesn't support property or method 'includes'
Can someone help here ?
I think the one you are missing is actually Array.includes.
I am using nextjs, with core-js#3, and in my polyfills I had to add
import 'core-js/features/object/values';
import 'core-js/features/object/entries';
import 'core-js/features/object/get-own-property-symbols';
import 'core-js/features/array/includes';
after these, I was able to make it work on IE11.
Related
I'm trying to lazy load routes in a Vue 2 application following the guides but webpack is not creating the chunks.
In my router file
const Home = () => import(/* webpackChunkName: "Home" */'#/features/titles/views/Home.vue');
My vue config's file is already removing the prefetch - and preload - plugin (as suggested here)
config.plugins.delete('prefetch');
but the output from the build task is always the same:
File Size Gzipped
dist/app.js 2024.66 KiB 452.42 KiB
The vue version is 2.6.1 and vue-router, 3.0.7.
The project has Typescript set up and I don't know f there is any relation, because in others similars projects with plain js, the lazy load in routes works fine.
Anyone has any ideia of what could be wrong in the implementation/configuration?
You can try a different config, something like this:
module.exports =
{
configureWebpack: (config) =>
{
config.optimization = {
// runtimeChunk: 'single',
moduleIds: 'hashed',
splitChunks:
{
automaticNameDelimiter: '_',
chunks: 'all',
maxInitialRequests: 5,
minSize: 5000,
// maxSize: 250000,
cacheGroups:
{
default:
{
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
vendor:
{
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]/,
name(module)
{
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like # symbols
return `vendors_${packageName.replace('#', '')}`;
},
},
},
},
};
},
chainWebpack: config =>
{
config.resolve.symlinks(false);
if (process.env.NODE_ENV === 'development')
{
config.module.rule('eslint').use('eslint-loader').loader('eslint-loader').tap(options =>
{
delete options.cacheIdentifier;
options.cache = false; // otherwise on each restart cached errors won't be shown !!!
return options;
});
}
config.module.rule('vue').use('vue-loader').loader('vue-loader').tap(options =>
{
delete options.cacheDirectory;
return options;
});
config.module.rule('vue').uses.delete('cache-loader');
config.module.rule('js').uses.delete('cache-loader');
config.plugins.delete('prefetch'); // for async routes
config.plugins.delete('preload'); // for CSS
// condense whitespace in templates
config.module.rule('vue').use('vue-loader').tap(options =>
{
options.compilerOptions = { whitespace: 'condense' };
return options;
});
return config;
}
};
I am currently using dotenv but there seems to be some caching issue with the #env. So wanted to try using process.env but it returns undefined. I am using expo, dotenv and webpack.
On app.js process.env.REACT_APP_KEY returns undefined, already restarted server, terminal and even my PC.
.env
REACT_APP_KEY=aaddddawrfffvvvvssaa
REACT_APP_KEY = aaddddawrfffvvvvssa
Webpack config
const createExpoWebpackConfigAsync = require('#expo/webpack-config');
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
const path = require('path')
config.module.rules = config.module.rules.map(rule => {
if (rule.oneOf) {
let hasModified = false;
const newRule = {
...rule,
oneOf: rule.oneOf.map(oneOfRule => {
if (oneOfRule.use && oneOfRule.use.loader && oneOfRule.use.loader.includes('babel-loader')) {
oneOfRule.include = [
path.resolve('.'),
path.resolve('node_modules/#ui-kitten/components'),
]
}
if (oneOfRule.test && oneOfRule.test.toString().includes('svg')) {
hasModified = true;
const test = oneOfRule.test.toString().replace('|svg', '');
return {...oneOfRule, test: new RegExp(test)};
} else {
return oneOfRule;
}
})
};
// Add new rule to use svgr
// Place at the beginning so that the default loader doesn't catch it
if (hasModified) {
newRule.oneOf.unshift({
test: /\.svg$/,
exclude: /node_modules/,
use: [
{
loader: '#svgr/webpack',
}
]
});
}
return newRule;
} else {
return rule;
}
});
return config;
};
babel config
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin',
['module:react-native-dotenv', {
'moduleName': '#env',
'path': '.env',
"blocklist": null,
"allowlist": null,
"safe": true,
"allowUndefined": false,
}]
],
};
};
If it matters (for dotenv)
declare module '#env' {
export const API_ENDPOINT: string;
}
Also tried process.env.NODE_ENV (which is working and prints "development" as output). Only process.env.VARIABLE_NAME is undefined
Maintainer here! process.env support in react-native-dotenv was just added this month https://github.com/goatandsheep/react-native-dotenv/issues/187
I work with Vue3 in TS (last vue-cli).
I want to get all nodes (vnodes) elements when vue-loader compile .vue file.
I need to read nodes attributes and remove all "data-test".
I have try in vue.config.js to use :
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
// .loader('vue-loader') // same with
.tap((options) => {
options.compilerOptions = {
...(options.compilerOptions || {}),
modules: [ // never enter here
{
preTransformNode(node) {
// if (process.env.NODE_ENV === 'production') {
const { attrsMap, attrsList } = node
console.log(node)
if (attrsMap['qa-id']) {
delete attrsMap['qa-id']
const index = attrsList.findIndex(
(x) => x.name === 'data-test'
)
attrsList.splice(index, 1)
}
// }
return node
}
}
]
}
return options
})
}
}
I know the transformation is done inside vue-template-compiler.
How can I enter in compile hook ?
I have try to use preTransformNode in module but that fail.
Sources :
https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler#readme
https://vue-loader.vuejs.org/options.html
The main problem here is that you are working with vue-template-compiler documentation, but that package is the compiler for Vue 2!
In Vue 3, compiler is split into multiple packages and is missing proper documentation as of now (or I was just unable to find it)
Also there were significant changes in the API - instead of modules, you pass nodeTransforms (source) and transforms are not objects, just functions.
Luckily for you, there is a interesting video on YT presented by Vue core member Rahul Kadyan which shows the exact use case you need (removing data-test attributes) - code
So I guess the code should look like this:
function removeDataTestAttrs(node) {
if (node.type === 1 /* NodeTypes.ELEMENT */) {
node.props = node.props.filter(prop =>
prop.type === 6 /* NodeTypes.ATTRIBUTE */
? prop.name !== 'data-test'
: true
)
}
}
module.exports = {
parallel: false, // !!IMPORTANT!! - see note below
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
options.compilerOptions = {
...(options.compilerOptions || {}),
nodeTransforms: [removeDataTestAttrs]
}
return options
})
}
}
Note - the problem mentioned in comments (solution working with serve but throws errors on build) is caused by Vue CLI using thread-loader for production builds. The problem is that while using thread-loader, you can not pass a functions as part of Webpack config (see this warning in the docs) so setting parralel: false is required to make it work....
Vite (Update - 22.06.22)
// vite.config.ts
function removeDataTestAttrs(node) {
if (node.type === 1 /* NodeTypes.ELEMENT */) {
node.props = node.props.filter(prop =>
prop.type === 6 /* NodeTypes.ATTRIBUTE */
? prop.name !== 'data-test'
: true
)
}
}
export default defineConfig(() => {
return {
plugins: [
vue({
template: {
compilerOptions: {
nodeTransforms: isProd ? [removeDataTestAttrs] : [],
},
},
}),
]
}
})
Vue-CLI 5 + Vue 3.2:
const { defineConfig } = require('#vue/cli-service');
function removeAttributesDuringBuild (node) {
const attributesToRemove = [
'data-test',
':data-test',
'v-bind:data-test',
'data-value',
':data-value',
'v-bind:data-value'
];
const nodeIsElement = node.type === 1; // ENUMS ARE STUPID
if (nodeIsElement) {
node.props = node.props.filter(function (prop) {
const propIsAttribute = prop.type === 6; // ENUMS ARE STUPID
const propIsDynamicAttribute = prop.name === 'bind';
if (propIsAttribute) {
const attributeName = prop.name;
return !attributesToRemove.includes(attributeName);
}
if (propIsDynamicAttribute) {
const attributeName = prop.arg?.content;
return !attributesToRemove.includes(attributeName);
}
return true;
});
}
}
module.exports = defineConfig({
lintOnSave: false,
transpileDependencies: true,
parallel: false, // disabled to allow for node transforms
chainWebpack: (config) => {
// Remove comments during build
config.optimization
.minimizer('terser')
.tap((args) => {
args[0].terserOptions.output = {
...args[0].terserOptions.output,
comments: false
};
return args;
});
// Remove dev attributes
config.module
.rule('vue')
.use('vue-loader')
.tap(function (options) {
options.compilerOptions = {
...(options.compilerOptions || {}),
nodeTransforms: [removeAttributesDuringBuild]
};
return options;
});
}
});
Vite 4 + Vue 2.7
import vue from '#vitejs/plugin-vue2';
import { defineConfig } from 'vite';
function removeAttributesDuringBuild (astEl) {
const attributesToRemove = [
'data-test',
':data-test',
'v-bind:data-test',
'data-value',
':data-value',
'v-bind:data-value'
];
function removeAttribute (attributesMap, attributesList, attributeToRemove) {
if (attributesMap[attributeToRemove]) {
delete attributesMap[attributeToRemove];
const index = attributesList.findIndex(function (attribute) {
return attribute.name === attributeToRemove;
});
attributesList.splice(index, 1);
}
}
if (process.env.NODE_ENV === 'production') {
const { attrsMap, attrsList } = astEl;
attributesToRemove.forEach(function (attributeToRemove) {
removeAttribute(attrsMap, attrsList, attributeToRemove);
});
}
return astEl;
}
export default defineConfig(() => {
return {
plugins: [
vue({
template: {
compilerOptions: {
modules: [
{
preTransformNode: removeAttributesDuringBuild
}
]
}
}
})
]
};
});
I am trying to use vite in one of my existing project. After long hard work I finally managed to make everything work in development mode. But, when I tried to test the app after building scripts with vite build, all dynamic imports failed for me. The issue was, all the import statements were being converted to __import__. If I manually replace __import__ with import on built bundles, then everything works. I tried removing #vitejs/plugin-legacy but, it still did not work.
Here is my vite.config.ts file
import { UserConfigFn } from 'vite';
import RubyPlugin from 'vite-plugin-ruby';
import FullReload from 'vite-plugin-full-reload';
import styleLint from '#amatlash/vite-plugin-stylelint';
import eslintPlugin from 'vite-plugin-eslint';
import legacy from '#vitejs/plugin-legacy';
import { resolve as _resolve, join } from 'path';
import * as tsconfig from './tsconfig.json';
const paths = tsconfig.compilerOptions.paths;
const defaultAlias = Object.keys(paths).reduce((acc, key) => {
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
const value = paths[key][0];
const path: string = key.replace('/*', '/');
acc.push({
find: path,
replacement: _resolve(__dirname, value.replace('/*', '/').replace('.//', './')) + '/',
});
return acc;
}, [] as any[]);
const configFn: UserConfigFn = ({ mode, command }) => {
const plugins =
mode === 'development' && command === 'serve'
? [
styleLint({
exclude: ['node_modules', 'public', 'plyr.css'],
}),
eslintPlugin({
fix: true,
exclude: ['node_modules', '**/legacy.js'],
}),
FullReload(['config/routes.rb', 'app/views/**/*']),
]
: [];
return {
plugins: [...plugins, legacy({}), RubyPlugin()],
css: {
postcss: '',
},
resolve: {
alias: [
...defaultAlias,
{
find: /~(.+)/,
replacement: join(process.cwd(), 'node_modules/$1'),
},
],
},
build: {
sourcemap: process.env.RAILS_ENV !== 'production',
polyfillDynamicImport: true,
rollupOptions: {
output: {
manualChunks: (id) => {
if (id.includes('node_modules')) {
if (id.includes('jquery')) {
return 'jquery';
}
if (
/creditcards|snabbdom-form|email-validator|format-numbe|form-serialize|phone-regex|email-regex|currency-regex|format-number|snake-case|number-format|superagent/.test(
id
)
) {
return 'formHelpers';
}
if (id.includes('chart.js')) {
return 'chartJs';
}
if (id.includes('moment')) {
return 'momentJs';
}
if (id.includes('imagesloaded')) {
return 'imagesLoaded';
}
if (id.includes('uuid')) {
return 'uuid';
}
if (id.includes('flimflam')) {
return 'flimflam';
}
if (/cropperjs|guillotine/.test(id)) {
return 'imageHelpers';
}
if (/ff-dashboard|ff-file-uploader/.test(id)) {
return 'ffDashboard';
}
return 'vendor';
}
},
},
},
},
clearScreen: false,
};
};
export default configFn;
Turns out it was because polyfillDynamicImport to true.
I'm doing a NextJS project using Ant design, Less. But I can't use CSS modules with Less even when I add
cssModules: true,
Here my next.config.js
const withPlugins = require("next-compose-plugins");
const withLess = require('#zeit/next-less')
const lessToJS = require('less-vars-to-js')
const fs = require('fs')
const path = require('path')
// Where your antd-custom.less file lives
const themeVariables = lessToJS(
fs.readFileSync(path.resolve(__dirname, './assets/antd-custom.less'), 'utf8')
)
module.exports = withLess({
cssModules: true,
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables, // make your antd custom effective
},
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/
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
},
})
index.js:
import styles from 'path-to-less.less'
<p className={styles.styleTab1} >Conntents </p>
but I it doesn't effect to my component.
Looks like this is a solution:
https://github.com/vercel/next.js/issues/8156#issuecomment-516009764
From my tries, this solution requires #zeit/next-less, #zeit/next-css, less, less-loader as dependencies 🤷🏽♂️.