Import markdown files as strings in Next.js - javascript

How can I import markdown files as strings in Next.js to work on client and server side?

You can configure your Next.js webpack loaders to load markdown files and return them as strings, for example:
docs/home.md
# Home
This is my **awesome** home!
pages/index.js
import React from 'react';
import markdown from '../docs/home.md';
export default () => {
return (
<div>
<pre>{markdown}</pre>
<small><i>Import and render markdown using Next.js</i></small>
</div>
);
};
package.json
{
"name": "example",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"file-loader": "^1.1.6",
"next": "^4.2.1",
"raw-loader": "^0.5.1",
"react": "^16.2.0",
"react-dom": "^16.2.0"
}
}
next.config.js
module.exports = {
webpack: (config) => {
return Object.assign({}, config, {
externals: Object.assign({}, config.externals, {
fs: 'fs',
}),
module: Object.assign({}, config.module, {
rules: config.module.rules.concat([
{
test: /\.md$/,
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]',
},
},
{
test: /\.md$/,
loader: 'raw-loader',
}
]),
}),
});
}
};
When running:
$ npm run dev
Something like this would appear:
With the markdown string you can do whatever you would like. For example, process it with marksy.

Quicker and "Next.js way" is to use plugin next-mdx
Documentation: https://github.com/vercel/next.js/tree/canary/packages/next-mdx
// next.config.js
const withMDX = require('#zeit/next-mdx')({
extension: /\.mdx?$/
})
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'mdx']
})

Just install raw-loader
npm install --save raw-loader
then edit your next.config.js
webpack: (config) => {
config.module.rules.push({
test: /\.md$/,
use: 'raw-loader',
});
return config;
},

Updates: emit-file-loader not strictly required, raw-loader deprecated in favor of asset modules
Some updates to https://stackoverflow.com/a/47954368/895245 possibly due to newer developments:
asset modules superseded raw-loader: https://stackoverflow.com/a/47954368/895245 No need to install any extra packages for that anyomore
emit-file-loader does not seem necessary anymore, not sure if it was needed, or if it is for something more specialized
so we can simplify things slightly to:
pages/index.js
import world from '../world.md'
export default function IndexPage() {
return <div>hello {world}</div>
}
next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.module.rules.push(
{
test: /\.md$/,
// This is the asset module.
type: 'asset/source',
}
)
return config
},
}
package.json
{
"name": "test",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "12.2.0",
"react": "17.0.2",
"react-dom": "17.0.2"
}
}
world.md
my md world
Getting it to work from Typescript
Unfortunately boch raw-loader and asset modules require a bit more work from typescript: https://github.com/webpack-contrib/raw-loader/issues/56#issuecomment-423640398 You have to create a file:
global.d.ts
declare module '*.md'
Otherwise the import will fail with:
Type error: Cannot find module '../world.md' or its corresponding type declarations.
Full example:
global.d.ts
declare module '*.md'
pages/index.tsx
import world from '../world.md'
export default function IndexPage() {
const what: string = 'my'
// Would fail on build as desired.
// const what2: int = 'world2'
return <div>hello {what} {world}</div>
}
next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.module.rules.push(
{
test: /\.md$/,
type: 'asset/source',
}
)
return config
},
}
package.json
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"type-check": "tsc"
},
"dependencies": {
"next": "v12.2.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"#types/node": "12.12.21",
"#types/react": "17.0.2",
"#types/react-dom": "17.0.1",
"typescript": "4.0"
}
}
world.md
my md world

Related

Vue loader 17.0.0 + Webpack 5.74.0 - Module build failed

I am trying to use vue-loader with my SPA VUE APP, And I'm getting the following error.
ERROR in ./app2.vue
Module build failed (from ./node_modules/vue-loader/dist/index.js):
TypeError: Cannot read properties of undefined (reading 'styles')
at Object.loader (/Users/daniel.bachnov/docker/qhs3-admin/frontend/node_modules/vue-loader/dist/index.js:70:34)
# ./main.js 1:0-29 14:8-11
webpack 5.74.0 compiled with 1 error and 3 warnings in 3312 ms
For eliminating app code noise, I created very simple component app2.vue:
And tried to connect it to my main.js entry point file.
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<template>
<button #click="count++">You clicked me {{ count }} times.</button>
</template>
main.js
import App from './app2.vue';
import Router from './router/router.js';
import Store from './store/index.js';
Vue.use(Vuetify)
Vue.use(VueRouter);
const app = new Vue({
router: Router.router,
store: Store,
el: '#app',
vuetify: new Vuetify(),
components: {
App,
}
});
webpack.config.js:
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
mode: 'production',
entry: './main.js',
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './../src/public/dist/'),
publicPath: "/dist/"
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// make sure to include the plugin!
new VueLoaderPlugin()
]
};
package.json
{
"name": "app",
"version": "1.0.0",
"description": "app",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"build": "webpack"
},
"author": "daniel bach",
"license": "ISC",
"dependencies": {
"#mdi/js": "^5.9.55",
"#vue/composition-api": "1.0.4",
"#vuetify/cli-plugin-utils": "^0.0.9",
"apexcharts": "^3.27.3",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-apexcharts": "^1.6.2",
"vue-router": "^3.2.0",
"vuetify": "^2.4.0",
"vuex": "^3.4.0",
"vue-loader": "^17.0.0"
},
"devDependencies": {
"vue-loader": "^17.0.0",
"vue-template-compiler": "^2.7.13",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"keywords": []
}
Do you have any idea why I keep getting this error?
vue-loader 16+ isn't compatible with vue 2.x
The vue-template-compiler / #vue/sfc-compiler has the following API in vue 2.7 (and 2.6):
https://github.com/vuejs/vue/blob/ca11dc6a86f26accc893c1ce5b611dc84a2e7c2d/packages/compiler-sfc/src/parse.ts#L33
for vue 3, the api changes, and the vue-loader also changes accordingly in 16+: https://github.com/vuejs/vue-loader/blob/1b1a195612f885a8dec3f371edf1cb8b35d341e4/src/index.ts#L92
So you need to use vue-loader 15.x
I encountered a similar issue once.Try reinstalling webpack npm install webpack#5.74.0 --save . It should work. If however it didn't, try lowering the version a bit.
Also try to:
delete node_modules folder and package-lock.json
run npm install again

Jest Setup with Next.js fails after it seems to add a react import to index.test.js

Hi I have been stewing over this for the last couple of days. I realise this is a common error with various solutions.
I have the dreaded:
Jest encountered an unexpected token
/__tests__/index.test.js:16
import React from "react";
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1796:14)
I have read a few posts and the docs in next and jest.
package.json:
{
"name": "some-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest --watch"
},
"dependencies": {
"next": "12.1.6",
"react": "18.1.0",
"react-dom": "18.1.0"
},
"devDependencies": {
"#babel/plugin-syntax-jsx": "^7.17.12",
"#babel/preset-env": "^7.18.2",
"#babel/preset-react": "^7.17.12",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#types/jest": "^28.1.3",
"#types/node-fetch": "^2.6.2",
"babel-jest": "^28.1.1",
"eslint": "8.16.0",
"eslint-config-next": "12.1.6",
"identity-obj-proxy": "^3.0.0",
"jest": "^28.1.1",
"jest-environment-jsdom": "^28.1.1",
"node-fetch": "^3.2.6",
"ts-jest": "^28.0.5",
"typescript": "^4.7.4"
},
"description": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).",
"main": "jest.config.js",
"repository": {
"type": "git",
},
"author": "",
"license": "ISC",
"bugs": {
},
}
index.test.js:
import { render, screen } from '#testing-library/react'
import Home from '../pages/index'
import '#testing-library/jest-dom'
import React from "react";
describe('Home', () => {
it('renders a h', () => {
render(<Home />)
const link = screen.getByRole('link', {
name: "Library",
})
expect(link).toHaveAttribute('href', '/storage-area')
})
});
jest.config.js:
module.exports = {
collectCoverage: true,
// on node 14.x coverage provider v8 offers good speed and more or less good report
coverageProvider: 'v8',
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
'!<rootDir>/out/**',
'!<rootDir>/.next/**',
'!<rootDir>/*.config.js',
'!<rootDir>/coverage/**',
],
moduleNameMapper: {
// Handle CSS imports (with CSS modules)
// https://jestjs.io/docs/webpack#mocking-css-modules
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// Handle CSS imports (without CSS modules)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
// Handle image imports
// https://jestjs.io/docs/webpack#handling-static-assets
'^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/__mocks__/fileMock.js`,
// Handle module aliases
'^#/components/(.*)$': '<rootDir>/components/$1',
},
// Add more setup options before each test is run
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jsdom',
transform: {
// Use babel-jest to transpile tests with the next/babel preset
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel', '#babel/preset-react',"#babel/preset-env" ]}],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
}
As I mentioned in the title the it seems that the error message suggests that the import is added by Next.js to the end of the index.test.js.
This was a problem due to the tests folder being nested in the directory above the root directory of the project. By the time I figured this out I had manipulated the jest.config.js transform: presets array property to contain imports that it didn't require in the standard jest/next setup.

vscode extension development: Add user defined data to vscode extension when package

I'm new to javascript and vscode extension development.
I'm trying to write a vscode extension, doing execSync a python script.
The file structure:
src:
|-- extension.ts
|-- sidebar_test.ts
|-- test_py.py
the content of extension.js file:
import * as vscode from 'vscode';
import * as sidebar from './sidebar_test';
import * as cp from "child_process";
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
console.log('process cwd: ', process.cwd(), '. env: ', process.env);
console.log('extension path: ', context.extensionPath);
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('dp2000-upgrade.DP2000Upgrade', function () {
vscode.window.showInputBox({
ignoreFocusOut: true,
placeHolder: 'IP Addr:Port',
}).then(function (input_str) {
let options = { env: {LD_LIBRARY_PATH: '/data/huangxiaofeng/work/tvm0.9dev0/build', PYTHONPATH: '/data/huangxiaofeng/work/tvm0.9dev0/python'} };
cp.execSync(`python ./test_py.py ${input_str}`, options); // TODO: call python script test_py.py
}).then(function (msg) {
console.log('User input:' + msg);
});
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate(): void {}
the content of test_py.py:
#! /usr/bin/python3.6
# -*- coding:utf-8 -*-
import tvm
import sys
import tvm.rpc
print('test_py.py will run...')
ip_addr, ip_port = sys.argv[1].split(':')
remote = tvm.rpc.connect(ip_addr, int(ip_port))
add_func = remote.get_function('rpc.test_add')
print(add_func(10, 20))
The content of package.json
{
"name": "dp2000-upgrade",
"displayName": "DP2000升级插件Demo",
"description": "vscode插件Demo, 借助TVM实现远程刷写 NNP main.hex",
"publisher": "intellif",
"version": "0.0.1",
"engines": {
"vscode": "^1.63.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:dp2000-upgrade.DP2000Upgrade",
"onView:sidebar_test_id1"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "dp2000-upgrade.DP2000Upgrade",
"title": "Upgrade DP2000"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile && npm run lint",
"lint": "eslint src --ext ts",
"package": "npm ci && rimraf *.vsix && vsce package && vsce ls"
},
"devDependencies": {
"#types/vscode": "^1.63.0",
"#types/glob": "^7.2.0",
"#types/mocha": "^9.0.0",
"#types/node": "14.x",
"#typescript-eslint/eslint-plugin": "^5.9.1",
"#typescript-eslint/parser": "^5.9.1",
"eslint": "^8.6.0",
"glob": "^7.2.0",
"mocha": "^9.1.3",
"typescript": "^4.5.4",
"#vscode/test-electron": "^2.0.3"
},
"repository": {
"type": "git",
"url": "https://gitee.com/vaughnHuang/vscode_ext_sidebar_test"
}
}
When package the project to .vsix, the test_py.py not included.
So my question is: how to include src/test_py.py into the .vsix?

React - Babel Polyfill doesn't prevent exception on Set or Weakmap for some reason, but does fill Promise

I am trying to provide some sort of cross compatibility with IE 10. I have used the Babel Polyfill to get past a Promise exception for IE 11, but for IE 10 I am getting exceptions for Set and Weakmap which babel polyfill should correct as it was my understanding that these were included as well.
This was my first React/React-static project, so flying by the seat of my pants to be honest so hope someone can help/explain things in a simple clear fashion.
FYI: Set is undefined in the main.js file produced by react-static build. And Weakmap is found in the hot-reloader module which is only a problem in dev mode.
My App.js file:
import "babel-polyfill";
import React from "react";
import { Router, Link } from "react-static";
import { hot } from "react-hot-loader";
import Routes from "react-static-routes";
import "./sass/app.scss";
import "./sass/_base.scss";
import "./sass/_layout.scss";
import "./sass/_utilities.scss";
import "./sass/main.scss";
import "./sass/_components.scss";
const App = () => (
<Router>
<div>
<Routes />
</div>
</Router>
);
export default hot(module)(App);
My static.config.js file:
import ExtractTextPlugin from "extract-text-webpack-plugin";
export default {
getSiteData: () => ({
title: "React Static"
}),
getRoutes: async () => {
// const { data: posts } = await axios.get(
// "https://jsonplaceholder.typicode.com/posts"
// );
return [
{
path: "/",
component: "src/containers/Home"
},
{
path: "/about",
component: "src/containers/About"
},
{
path: "/services",
component: "src/containers/Services"
},
{
path: "/cases",
component: "src/containers/Cases"
},
{
path: "/process",
component: "src/containers/Process"
},
{
path: "/contact",
component: "src/containers/Contact"
},
{
path: "/contactsent",
component: "src/containers/Contactsent"
},
{
is404: true,
component: "src/containers/404"
}
];
},
webpack: (config, { defaultLoaders, stage }) => {
let loaders = [];
if (stage === "dev") {
loaders = [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "sass-loader" }
];
} else {
loaders = [
{
loader: "css-loader",
options: {
importLoaders: 1,
minimize: stage === "prod",
sourceMap: false
}
},
{
loader: "sass-loader",
options: { includePaths: ["src/", "src/sass/"] }
}
];
// Don't extract css to file during node build process
if (stage !== "node") {
loaders = ExtractTextPlugin.extract({
fallback: {
loader: "style-loader",
options: {
sourceMap: false,
hmr: false
}
},
use: loaders
});
}
}
config.module.rules = [
{
oneOf: [
{
test: /\.s(a|c)ss$/,
use: loaders
},
defaultLoaders.cssLoader,
defaultLoaders.jsLoader,
defaultLoaders.fileLoader
]
}
];
return config;
}
};
My package.json:
{
"name": "react-static-example-basic",
"version": "1.0.1",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "react-static start",
"stage": "react-static build --staging",
"build": "react-static build",
"serve": "serve dist -p 3000"
},
"dependencies": {
"axios": "^0.16.2",
"core-js": "^3.0.1",
"es6-promise": "^4.2.6",
"promise-polyfill": "8.1.0",
"raf": "^3.4.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router": "^4.2.0",
"react-spring": "^8.0.5",
"react-static": "^5.9.7"
},
"devDependencies": {
"babel-polyfill": "^6.26.0",
"eslint-config-react-tools": "1.x.x",
"extract-text-webpack-plugin": "^3.0.2",
"node-sass": "^4.7.2",
"sass-loader": "^6.0.6",
"serve": "^6.1.0"
}
}
It may be worth trying to separately instal core-js include such modules in the assembly:
npm i --save core-js
import "core-js/es/set";
import "core-js/es/weak-map";
If that doesn't help try use polyfill.io:
Add yor html it:
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=WeakMap%2CWeakSet%2CSet"></script>
Not familiar with react-static as such, but from what I experienced with my projects with react and webpack:
the babel polyfill needs to go into the html page as a first script tag, and could not be packaged as part of webpack (I do not recall the exact reasons)
On projects not involving babel I had success convincing IE10 to play ball using: https://github.com/paulmillr/es6-shim

Webpack bundled file not generated

I am just new to webpack and react , just going through the docs and created a example to work. Unfortunately i got stuck and not able to proceed . Th problem is the bundled file is not generated.
The files i created is
package.json
{
"name": "rohith",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1",
"webpack": "^1.13.3",
"webpack-dev-server": "^1.16.2"
}
}
webpack.config.js
module.export = {
entry : './main.js',
output : {
path : './',
filename : 'index.js'
},
devServer : {
inline : true,
port : 3333
},
module : {
loaders : [
{
test : /\.js$/,
exclude : /node_modules/,
loader : 'babel',
query : {
presets : ['es2015','react']
}
}
]
}
}
App.js
import React from 'react';
class App extends React.Component {
render(){
return <div>Hello</div>
}
}
export default App
main.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />,document.getElementById('app'));
index.html
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>Setup</title>
</head>
<body>
<div id = "app"></div>
<script src ="index.js"></script>
</body>
</html>
I am getting that bundle is valid, but no index.js is generated.
can't run in localhost 3333
Thanks,
I think the problem is that you are not giving the absolute output path.
Try this:
var path = require('path');
module.exports = {
entry : './main.js',
output : {
path : path.join(__dirname, './'),
filename : 'index.js'
},
devServer : {
inline : true,
port : 3333
},
module : {
loaders : [
{
test : /\.js$/,
exclude : /node_modules/,
loader : 'babel',
query : {
presets : ['es2015','react']
}
}
]
}
}
Hope it helps :)
In webpack.config.js, use module.exports instead of module.export. See Output filename not configured Error in Webpack
Also be noticed that your package.json lacks some dependencies. Here is the updated package.json that works:
{
"name": "rohith",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1",
"webpack": "^1.13.3",
"webpack-dev-server": "^1.16.2"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.18.2",
"babel-loader": "^6.2.8",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0"
}
}
Replace your scripts object with the below:
"scripts": {
"start": "npm run build",
"build": "webpack -p && webpack-dev-server"
},
Then, run $ npm start
For me the problem was with package.json under that "scripts"
Here is the fix:
Inside your package.json file, under script add the following:
"scripts": {
"start": "webpack-dev-server",
"build": "webpack -p"
}
First I ran the build then start.
yarn build
if you first build then your bundle.js file will be created and after that you can use this command:
yarn start
In case of no output file (bundle.js) and a successful build
Hash: 77a20ba03ab962a1f5be
Version: webpack 4.41.0
Time: 1039ms
Built at: 10/04/2019 5:24:48 PM
Asset Size Chunks Chunk Names
main.js 1.09 MiB main [emitted] main
Entrypoint main = main.js
[./react_rest/frontend/src/index.js] 35 bytes {main} [built]
+ 12 hidden modules
webpack :
module.exports = {
entry: './react_rest/frontend/src/index.js',
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}]
},
output: {
filename: 'main.js'
}
};
Try to use var path = require('path'); and allocating output directory
var path = require('path');
module.exports = {
entry: './react_rest/frontend/src/index.js',
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}]
},
output: {
path: path.join(__dirname,'./react_rest/frontend/static/frontend/'),
filename: 'main.js'
}
};

Categories